Framework
스프링(Spring) AOP : AspectJ Pointcut 표현식 (Feat. 프로젝트에서 꼭 활용할 내용들)
매료매료
2020. 3. 31. 15:01
1. AOP(Aspect Oriented Programming)
- 주기능과 보조기능을 분리한 후 선택적으로 메소드에 적용
- XML(aound advice) 스키마 기반
- aspect(클래스) 애노테이션 기반
// XML 설정파일
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 공통 기능을 제공할 클래스를 빈으로 등록 -->
<bean id="profiler" class="spring.apo.ex01.advice.ProfilerAdvice" />
<!-- Aspect 설정: Advice를 어떤 Pointcut에 적용할 지 설정 -->
<aop:config>
<aop:aspect id="traceAspect" ref="profiler">
// Aspect J의 표현식
<aop:pointcut id="publicMethod" expression="execution(public * spring.apo.ex01..*(..))" />
// pointcut 이라는 호출할 메소드의 범위를 결정하고 / * - 모든 파라미터를 가진 / (..) - 하위 패키지까지 포함.
<aop:around pointcut-ref="publicMethod" method="trace" />
// around - 호출시점 / trace - 공통기능
</aop:aspect>
</aop:config>
<bean id="readArticleService" class="spring.apo.ex01.component.ReadArticleServiceImpl">
<property name="articleDao" ref="articleDao" />
</bean>
<bean id="articleDao" class="spring.apo.ex01.component.ArticleDaoImpl" />
</beans>
// Advice 클래스
// Aound Advice
// 다른 advice는 대상객체 호출을 spring FW이 실행
public class ProfilerAdvice {
// ProceedingJoinPoint joinPoint 파라미터이면 -> Around Advice이고,
public Object trace(ProceedingJoinPoint joinPoint) throws Throwable {
String signatureString = joinPoint.getSignature().toShortString();
System.out.println(signatureString + " 시작");
long start = System.currentTimeMillis();
try {
// Around Advice이면, proceed() 메소드 제공한다.
Object result = joinPoint.proceed(); // aspect가 적용될 대상 객체 호출
return result;
} finally {
long finish = System.currentTimeMillis();
System.out.println(signatureString + " 종료");
System.out.println(signatureString + " 실행 시간 : " + (finish - start) + "ms");
}
}
}
2. AspectJ의 Pointcut 표현식
execution(public void set*(..)) : 리턴타입이 void이고 메소드이름이 set으로 시작하고 파라미터가 0개이상인 매소드 호출. 파라미터 부분에 ..을 사용하여 0개 이상인 것을 표현
execution(*.net.spring.*.*()) : spring 패키지의 파라미터가 없는 모든 메소드, 모든 리턴타입
execution(*.net.spring..*.*(..)) : spring 패키지의 파라미터가 0개 이상이고 패키지 부분에 ..을 표현하여 하위패키지를 표현
execution(Integer net.spring.boid.WriteArticleService.write(..)) : 리턴타입이 Integer인 WriteArticleService IF의 write() 메소드 호출
execution(* get*(*)) : 이름이 get으로 시작하고 1개의 파라미터를 갖는 메소드 호출
execution(* get*(*,*)) : 이름이 get으로 시작하고 2개의 파라미터를 갖는 메소드 호출
execution(* read*(Integer, ..)) : 이름이 read로 시작하고, 첫번째 파라미터 타입이 Integer이며, 1개의 파라미터를 갖는 메소드 호출
스프링(Spring) AOP : AspectJ Pointcut 표현식
execution 명시자
- Advice를 적용할 메서드 지정
- 기본 형식 :
-> "*" 는 모든 값을 의미
-> ".." 는 0개 이상 의미
execution([수식어] [리턴타입] [클래스이름] [이름]([파라미터])
수식어
- 생략가능
- public, protected 등등
리턴타입
- 메서드의 리턴타입 지정
클래스이름, 이름
- 클래스의 이름 및 메서드의 이름 지정
파라미터
- 메서드 파라미터 지정
ex)
execution(* some.package.*.*())
- some.package 패키지 내
- 파라미터가 없는 모든 메서드 호출
execution(* some.package..*.*(..))
- some.package 패키지와 하위 패키지에 있는
- 파라미터가 0개 이상인 모든 메서드 호출
execution(String some.package.SomeService.someMethod(..))
- 리턴 타입이 String,
- some.package.SomeService 인터페이스 내
- 파라미터가 0개 이상인 someMethod 메서드 호출
execution(* some*(*))
- 메서드 이름이 some으로 시작되고,
- 파라미터가 1개인 메서드 호출
execution(* some*(*, *))
- 메서드 이름이 some으로 시작되고,
- 파라미터가 2개인 메서드 호출
execution(* some*(String, ..))
- 메서드 이름이 some으로 시작되고,
- 첫번째 파라미터 타입이 String,
- 파라미터가 1개 이상인 메서드 호출
within 명시자
- 특정 타입(Interface, Class)에 속하는 메서드를 Pointcut으로 지정
ex)
within(some.package.SomeService)
- SomeService 인터페이스 내 모든 메서드 호출
within(some.package.*)
- some.package 패키지 내 모든 메서드 호출
within(some.package..*)
- some.package 패키지 및 하위 패키지 내 모든 메서드 호출
bean 명시자
- Spring 2.5부터 제공
- 스프링 빈 이름을 이용하여 Pointcut 지정
- 빈 이름의 패턴을 설정
ex)
bean(someServiceBean)
- 이름이 someServiceBean인 빈의 메서드 호출
bean(*SomeService)
- 이름이 SomeService로 끝나는 빈의 메서드 호출
- 표현식에는 '&&' 및 '||' 연산자를 이용
-> 각각의 표현식을 연결
-> and 연산과 or 연산
-> and면 양쪽 표현식을 모두 만족하는
-> or이면 양쪽 표현식중 어느 하나를 만족하는
ex)
@Before("execution(public !void get*(..)) || execution(public !void set*(..))")
public void someBeforeAdviceMethod(JoinPoint joinPoint){
// 대상 객체 메서드 실행전 수행할 공통기능
}
@After("execution(public !void get*(..)) && execution(public * get*(..))")
public void someAfterAdviceMethod(JoinPoint joinPoint){
// 대상 객체 메서드 실행후 수행할 공통기능
}
- XML 스키마에서 Aspect를 설정할 경우
-> '&&', '||' 사용가능 ('&&' 식으로)
-> 'and', 'or'로 사용가능
<aop:pointcut id="somePointcut"
expression="execution(public !void get*(..)) && execution(public * get*(..))" />
<aop:pointcut id="somePointcut"
expression="execution(public !void get*(..)) and execution(public * get*(..))" />
출처: https://groovysunday.tistory.com/204?category=312452 [성냥의 불친절한 IT 이야기]