스프링 에노테이션기반 aop를 학습한다.
스프링 부트기반에서 스프링 aop를 사용하기위해서
spring-boot-starter-aop 의존이필요하다.
-
spring-aop
-
aspectj-weaver
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
사용 방법..?
공통기능 클래스에는 @Aspect로 공통기능 클래스임을 알리며 Bean 으로 등록해야만 한다.
필요한 정보는 다음과 같다.
-
해야할 일 : Advice
-
어디에 적용할 것인가 : PointCut
@ComponentScan 의 속성 값에 includeFilters 값을 주어 @Filter 에 어노테이션을 지정하여 @Aspect 를 스캔해도 무방하다.
@Aspect
@Component
public class PerfAspect {
}
핵심 객체와 표현식은..?
Object 메서드명 (ProceedingJoinPoint) 의 메서드 시그니쳐를 가진 메서드를 작성하는데,
ProceedingJoinPoint 는 Advice가 적용되는 대상이라고 보면 좋다.
-
@Around : 메서드 실행 전, 후, 예외발생, 리턴 시 에 모두 적용하며 해당 메서드를 감싸는 느낌이다.
- @Before : 메서드 실행 전
- @AfterThrowing : 예외 송출
- @AfterReturning : 무사히 리턴시
이정도로 알고있는데 , 직접 적용해보긴 했으나, @Around 가 좋더라...라는 개인적 의견...토이프로젝트에서 했지만..
이전 글에 Signature 객체와 ProceedingJoinPoint 객체의 메서드를 기술했으니, 이번에는 생략하려한다.
익숙했던 Spring-Aop 기초 이론, 충격적이고 새로운 것은 명시자.
처음엔 AOP 기존 용어와 execution 명시자의 표현식을 외우기 위해 입에 붙여서 중얼거렸다.
-
public은 spring-aop 기준으로 반드시 설정되야하므로 생략해도 좋고...
-
리턴타입 | 패키지 | 클래스 | 메서드명 (파라미터) 로 정의할 수 있다.
-
* 은 모든 것을 의미하며 ..은 0개 이상을 의미한다. . 은 하나 구체적으로 파라미터를 명시하거나 조합할 수 있던 걸로 기억한다.
-
이 것이 참 오묘...했던게, 내가 원치않는 메서드까지 aop 적용대상이 되는 경우가 있더라. 그리고 이번기회에 새로운 명시자를 배우게 되어 기뻤다.
-
@annotation 명시자는 해당 어노테이션의 이름을 속성 값으로 주어 어노테이션이 적용된 joinPoint에만 Advice를 적용한다.
-
bean 명시자는 빈의 identifier 를 속성 값으로 주어 해당 빈의 모든 public 메서드가 PointCut이 된다.
@Aspect
@Component
public class PerfAspect {
@Around("execution(* me.soomin.demospring51.aop.SimpleEvent.*(..))")
public Object logPerf1(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - start);
return retVal;
}
@Around("@annotation(PerfLogging)")
public Object logPerf2(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - start);
return retVal;
}
@Around("bean(simpleEvent)")
public Object logPerf3(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - start);
return retVal;
}
@Before("bean(simpleEvent)")
public void hello(){
System.out.println("Hello");
}
}
기억을 되살려보려 포인트컷 재사용 방법을 다시 확인.
@Pointcut("@annotation(PerfLogging)")
public void loggingPoint(){
}
@Around("loggingPoint()")
public Object logPerf2(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object retVal = pjp.proceed();
System.out.println(System.currentTimeMillis() - start);
return retVal;
}
주목했던 명시자는 @annotation 명시자.
일단, @annotation 명시자는 직접 정의한 어노테이션을 적용할 수 있다는 점이 놀라웠다.
어노테이션을 만들때 주의할 점 은 이런 부분이라고 하신다.
-
@Retention 의 속성에 RetentionPolicy를 CLASS 이상으로 줘야한다는 점.
-
RetentionPolicy 는 에노테이션 정보를 얼마나 유지할 것인가 이다. / default = RetentionPolicy.CLASS
-
즉 RetentionPolicy.CLASS 는 컴파일 후의 바이트 코드에서도 에노테이션 정보를 남기겠다는 것이다.
-
RetentionPolicy.SOURCE , 컴파일 후에 어노테이션 정보는 사라진다. 그렇기에 어노테이션 명시자에 적합하지 않다.
/**
* 이 에노테이션을 사용하면 성능을 로깅해줍니다.
*/
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface PerfLogging {
}
포인트컷 조합식으로는 && , || , ! 이 있다. ..처음봐서..너무 놀랍다.
@Pointcut("@annotation(PerfLogging)&&@annotation(Deprecated)")
public void loggingPoint(){
}
'springframework' 카테고리의 다른 글
Web Mvc (0) | 2020.10.08 |
---|---|
o.s.w IoC 핵심기술. Null-Safety (0) | 2020.09.19 |
o.s.w IoC 핵심기술. 프록시 기반의 AOP (0) | 2020.09.17 |
o.s.w IoC 핵심기술. AOP 개요. (0) | 2020.09.17 |
o.s.w IoC 핵심기술. SpEL (스프링 Expression Language) (0) | 2020.09.17 |