Spring AOP - @AOP

  • Annotation 기반의 Spring @AOP


Spring AOP 사용해보기

  • 이전 포스트 에서 사용한 EventService, SimpleEventService, AppRunner가 있어야 합니다.


1. Dependency 추가

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>


2. Aspect 정의, Pointcut 정의

  • @Aspect
  • 빈으로 등록해야 하므로 @Component도 추가.

PerformanceAspect.java

@Component
@Aspect
public class PerformanceAspect {

   // Around는 메서드를 감싸는 형태로 적용된다. (메서드호출 이전, 이후, 에러가 났을때 특정한 작업 등 다용도로 쓰일 수 있는 Annotation이다.
   // Around 뒤에는 Pointcut 이름 혹은 Pointcut을 직접 정의할 수 있다.
   @Around("execution(* com.springstudy..*.EventService.*(..))")
   public Object logPerformance(ProceedingJoinPoint pip) throws Throwable {
       // ProceedingJoinPoint pip 는 대상 메서드 자체를 의미
       long beginTime = System.currentTimeMillis();
       Object letVal = pip.proceed(); // 메서드 호출
       System.out.println(System.currentTimeMillis() - beginTime);
       return letVal;
   }

}

위와 같이 메서드를 실행한다면 코드의 중복 없이 시간을 출력하는 Aspect를 사용할 수 있다.

  • 하지만 EventService 전체의 메서드에 적용이 되었다.


Pointcut 정의 방법


1. execution

  • 위의 방법과 같다.


2. @annotation

  • Annotation을 만들어 Pointcut을 정의할 수 있다. 우선 Annotation을 생성한다.

PerformanceLogging.java

@Documented // javadoc 만들때 Dacumantation 될 수 있게 만듬.
@Target(ElementType.METHOD) // 타겟은 메서드
@Retention(RetentionPolicy.CLASS) // - Default가 CLASS
// Annotation에서  RetentionPolicy는 Annotation 정보를 얼마나 유지할 것인가 ? (Class File에 유지)
// RetentionPolicy.SOURCE 컴파일 하면 사라짐
public @interface PerformanceLogging {
}

위와 같이 Annotation을 생성한 후 Pointcut에 @annotation을 명시해준다.


PerformanceAspect.java

@Component
@Aspect
public class PerformanceAspect {

    @Around("@annotation(PerformanceLogging)")
    // PerformanceLogging Annotation이 붙은 메서드에만 적용
    public Object logPerformance(ProceedingJoinPoint pip) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object letVal = pip.proceed();
        System.out.println(System.currentTimeMillis() - beginTime);
        return letVal;
    }

}


마지막으로 사용할 메서드에 PerformanceLogging Annotation을 적용한다.


@Service
public class SimpleEventService implements EventService {

    @PerformanceLogging
    @Override
    public void createEvent() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Created an event");
    }

    @PerformanceLogging
    @Override
    public void publishEvent() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Published an event");
    }

    @Override
    public void deleteEvent() {
        System.out.println("Deleted an event");
    }
}


위와 같이 Annotation을 만들어 사용한다면 좀더 명시적이고 원하는 메서드에 간편하게 사용이 가능하다!!


3. Bean

  • pointcut에 Bean을 명시하여 해당 Bean 전체에 적용할 수 있다.

PerformanceAspect.java

@Component
@Aspect
public class PerformanceAspect {

   @Around("bean(simpleEventService)")
   // PerformanceLogging Annotation이 붙은 메서드에만 적용
   public Object logPerformance(ProceedingJoinPoint pip) throws Throwable {
       // ProceedingJoinPoint pip 는 대상 메서드 자체를 의미
       long beginTime = System.currentTimeMillis();
       Object letVal = pip.proceed(); // 메서드 호출
       System.out.println(System.currentTimeMillis() - beginTime);
       return letVal;
   }

}


Advice의 종류

위에서 사용한 Around Annotation은 메서드를 감싸는 형태로 적용되며 다용도로 쓰일 수 있는 Annotation이다.

그 Advice는 아래와 같은 종류가 존재한다.

  • @Before
  • @AfterReturning
  • @AfterThrowing
  • @Around


이 외의 pointcut과 advice에 대한 정의는 Spring Document에서 확인할 수 있다.


Project Repository

  • https://github.com/Seongmun-Hong/SpringStudy


Reference

  • https://www.inflearn.com/course/spring-framework_core
Share :

Comments