커스텀 Spring AOP Annotation 구현하기

1. 소개

이 기사에서는 Spring의 AOP 지원을 사용하여 사용자 정의 AOP 주석을 구현할 것입니다.

먼저 AOP의 정의와 장점을 설명하면서 AOP에 대한 높은 수준의 개요를 제공합니다. 그 다음에는 주석을 단계별로 구현하여 점차적으로 AOP 개념에 대한보다 심층적 인 이해를 쌓을 것입니다.

그 결과 AOP에 대한 더 나은 이해와 향후 사용자 정의 Spring 어노테이션을 작성할 수있는 능력이 될 것입니다.

2. AOP 주석이란 무엇입니까?

요약하자면 AOP는 측면 지향 프로그래밍을 의미합니다. 기본적으로 이는 해당 코드를 수정하지 않고 기존 코드에 동작을 추가하는 방법입니다 .

AOP에 대한 자세한 소개를 위해 AOP 포인트 컷 및 조언에 대한 기사가 있습니다. 이 기사는 우리가 이미 기본적인 지식을 가지고 있다고 가정합니다.

이 기사에서 구현할 AOP 유형은 주석 기반입니다. Spring @Transactional 어노테이션을 사용했다면 이미 익숙 할 것입니다 .

@Transactional public void orderGoods(Order order) { // A series of database calls to be performed in a transaction }

여기서 핵심은 비 침습성입니다. 주석 메타 데이터를 사용하면 핵심 비즈니스 로직이 트랜잭션 코드로 오염되지 않습니다. 이를 통해 추론, 리팩터링 및 격리 테스트가 더 쉬워집니다.

때때로 Spring 애플리케이션을 개발하는 사람들은 이것이 어떻게 작동하는지에 대해 자세히 생각하지 않고 이것을 ' Spring Magic' 으로 볼 수 있습니다 . 실제로 일어나고있는 일은 특별히 복잡하지 않습니다. 그러나이 기사의 단계를 완료하면 AOP를 이해하고 활용하기 위해 고유 한 사용자 지정 주석을 만들 수 있습니다.

3. Maven 종속성

먼저 Maven 종속성을 추가하겠습니다.

이 예제에서는 구성 접근 방식에 대한 규칙으로 가능한 한 빨리 시작하고 실행할 수 있으므로 Spring Boot를 사용할 것입니다.

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE    org.springframework.boot spring-boot-starter-aop  

측면 구현을 시작하는 데 필요한 라이브러리를 가져 오는 AOP 스타터가 포함되어 있습니다.

4. 사용자 지정 주석 만들기

우리가 만들 어노테이션은 메소드를 실행하는 데 걸리는 시간을 기록하는 데 사용됩니다. 주석을 만들어 보겠습니다.

@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LogExecutionTime { } 

비교적 간단한 구현이지만 두 개의 메타 주석이 무엇에 사용되는지 주목할 가치가 있습니다.

@Target의 우리의 주석이 적용되는 위치 주석은 우리에게 알려줍니다. 여기서는 ElementType.Method 를 사용 합니다. 즉 , 메서드에서만 작동합니다. 다른 곳에서 주석을 사용하려고하면 코드가 컴파일되지 않습니다. 이 동작은 우리의 주석이 메서드 실행 시간을 기록하는 데 사용되기 때문에 의미가 있습니다.

그리고 @Retention 은 런타임에 JVM에서 주석을 사용할 수 있는지 여부를 나타냅니다. 기본적으로 그렇지 않으므로 Spring AOP는 주석을 볼 수 없습니다. 이것이 재구성 된 이유입니다.

5. 우리의 측면 만들기

이제 주석이 생겼으니 aspect를 만들어 보겠습니다. 이것은 우리의 교차 절단 문제를 캡슐화 할 모듈 일뿐입니다. 우리의 경우는 메서드 실행 시간 로깅입니다. 모든 것이 @Aspect로 주석이 달린 클래스입니다 .

@Aspect @Component public class ExampleAspect { }

@Component 주석 도 포함 시켰는데 , 우리 클래스도 감지 할 스프링 빈이어야하기 때문입니다. 본질적으로 이것은 우리가 커스텀 어노테이션을 주입하기를 원하는 로직을 구현할 클래스입니다.

6. 포인트 컷과 조언 만들기

이제 포인트 컷과 조언을 만들어 봅시다. 이것은 우리의 측면에있는 주석이 달린 메서드가 될 것입니다.

@Around("@annotation(LogExecutionTime)") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { return joinPoint.proceed(); }

기술적으로 이것은 아직 아무것도 동작을 변경하지 않지만 여전히 분석이 필요한 많은 작업이 진행되고 있습니다.

먼저 @Around로 메서드에 주석을 달았습니다. 이것이 우리의 조언이며, around advice는 메소드 실행 전후에 코드를 추가한다는 것을 의미합니다. 이전이후 와 같은 다른 유형의 조언이 있지만이 기사에서는 다루지 않습니다.

다음으로 @Around 주석에는 포인트 컷 인수가 있습니다. 우리의 pointcut은 ' @LogExecutionTime 주석이 달린 모든 메소드에이 조언을 적용하십시오 .'라고 말합니다 . 다른 유형의 포인트 컷이 많이 있지만 범위 인 경우 다시 제외됩니다.

logExecutionTime () 메소드 자체가 우리의 조언입니다. ProceedingJoinPoint 라는 단일 인수가 있습니다 . 우리의 경우 @LogExecutionTime 으로 주석이 달린 실행 메서드가 됩니다.

마지막으로 어노테이션이있는 메소드가 호출되면 우리의 조언이 먼저 호출됩니다. 그런 다음 다음에 할 일을 결정하는 것은 우리의 조언에 달려 있습니다. 우리의 경우, 우리의 조언을 호출하는 것보다 다른 아무것도 수행하지 않습니다 ()을 진행, 의인 원래 주석이 메소드를 호출합니다.

7. 실행 시간 기록

이제 우리는 골격을 갖췄습니다. 우리가해야 할 일은 조언에 로직을 추가하는 것뿐입니다. 이것은 원래 메서드를 호출하는 것 외에도 실행 시간을 기록하는 것입니다. 이 추가 동작을 우리의 조언에 추가해 보겠습니다.

@Around("@annotation(LogExecutionTime)") public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object proceed = joinPoint.proceed(); long executionTime = System.currentTimeMillis() - start; System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms"); return proceed; }

Again, we've not done anything that's particularly complicated here. We've just recorded the current time, executed the method, then printed the amount of time it took to the console. We're also logging the method signature, which is provided to use the joinpoint instance. We would also be able to gain access to other bits of information if we wanted to, such as method arguments.

Now, let's try annotating a method with @LogExecutionTime, and then executing it to see what happens. Note that this must be a Spring Bean to work correctly:

@LogExecutionTime public void serve() throws InterruptedException { Thread.sleep(2000); }

After execution, we should see the following logged to the console:

void org.baeldung.Service.serve() executed in 2030ms

8. Conclusion

이 기사에서는 Spring Boot AOP를 활용하여 커스텀 어노테이션을 생성했으며,이를 Spring Bean에 적용하여 런타임에 추가 동작을 주입 할 수 있습니다.

애플리케이션의 소스 코드는 GitHub에서 사용할 수 있습니다. 이것은있는 그대로 실행할 수있는 Maven 프로젝트입니다.