- 횡단 관심 (Crosscutting Concerns)
- 모든 메소드에 들어있는 공통된 로직을 의미한다.
- 핵심 관심 (Core Concerns)
- 각 메소드에만 들어 있는 핵심 관심 코드을 의미한다.
- 반복되는 횡단 관심을 모듈화를 통해 분리하고 재사용하는 것이다.
- Aspect(Advisor) : Pointcut과 Advice의 결합(모듈화), Pointcut의 시점에 Advice가 실행되는 것을 의미한다.
- Pointcut : 횡단 관심(Advice)이 일어나는 시점을 의미한다. (필터링된 JointPoint)
- Advice : 횡단 관심에 해당하는 실행될 공통 기능의 코드를 의미한다.
aop
사용 체크 (Eclipse 기준)<beans> <!--세부 내용 생략 -->
<!--횡단 관심에 해당하는 Advice 클래스 빈 등록-->
<bean id="id" class="클래스 패키지 주소"></bean>
<!--AOP 설정 -->
<aop:config>
<aop:pointcut id="allPointcut" expression="execution(* com.naver.biz..*Service.*(..))"/>
<aop:aspect ref="id">
<aop:after pointcut-ref="allPointcut" method="beanMethod"/>
</aop:aspect>
</aop:config>
</beans>
<aop:after ...>
는 동작 시점을 의미하며 before, after, after-returning, after-throwing, around 속성을 사용할 수 있다. (아래에서 더 설명)[리턴타입] [패키지 경로][클래스 이름].[메소드 이름 및 매개변수]
*
: 모든 리턴을 허용한다.- void : 리턴 타입이 void인 메소드 필터링한다.
- !void : 리턴 타입이 void가 아닌 메소드 필터링한다.
- com.naver.biz.users : 정확한 패키지명으로 필터링한다.
- com.naver.biz.. : com.naver.biz로 시작하는 모든 패키지를 필터링한다.
- com.naver..users : com.naver로 시작하는 패키지 중 패키지 마지막이 user인 패키지를 필터링한다.
- UserService : UserService 클래스를 필터링한다.
- *Service : 클래스 이름이 Service로 끝나는 클래스를 필터링한다.
- insertUser : insertUser 메소드를 필터링한다.
- insert* : insert로 시작하는 모든 메소드를 필터링한다.
- (..) : 모든 경우의 매개변수의 갯수와 타입 허용한다.
- (*) : 매개변수를 1개 받는 메소드를 필터링한다.
- (int, String) : int형, String형을 매개변수로 받는 메소드를 필터링한다.
expression="execution(void com.naver..*Impl.get*(..))"
- 리턴 타입이 void, com.naver.. 아래 모든 클래스 중 클래스 이름이 Impl로, 메소드 이름이 get으로 시작하는 모든 메소드를 필터링한다.
expression="execution(* com.kakao.biz.*.*user(*,*))"
- com.kakao.biz 아래 모든 클래스, user로 끝나는 메소드이며 매개변수를 2개 받는 메소드를 필터링한다.
- after-returning : 비즈니스 메소드 실행 후 데이터를 return하고 Advice에서 인자로 받아 사용 가능하다.
- .xml 파일에서 returning 속성으로 리턴할 데이터명을 설정할 수 있다. (유효성 검사에 사용할 수 있다.)
- 비즈니스 메소드의 리턴 타입이 void이면 NullPointerException이 일어나니 주의해야 한다.
- after-throwing : 비즈니스 메소드 실행시 예외 발생시 예외 객체를 return하고 Advice에서 인자로 받아 사용 가능하다.
- .xml 파일에서 throwing 속성으로 리턴할 예외 변수명을 설정할 수 있다.
- around Advice는 ProceedingJoinPoint 객체를 인자로 받아야 한다.
public Object aroundAdvice(ProceedingJoinPoint jp) throws Throwable{ String method =jp.getSignature().getName(); Object returnObj =null; System.out.println("비즈니스 메소드 사전처리") returnObj = jp.proceed(); System.out.println("비즈니스 메소드 사후처리") System.out.println(method+ "() 비즈니스 메소드 실행완료"); return returnObj; }
<aop:aspectj-autoproxy/>
을 설정해준다.(<aop:config>
는 없어도 된다.)@Service
를 붙여 bean 등록을 대체한다.@Aspect
를 붙여 Aspect 역할을 할 클래스임을 나타낸다.@Pointcut("execution(~)")
을 생성한다.
@Before("참조형 메소드명()")
@After("참조형 메소드명()")
@AfterReturning(pointcut="참조형 메소드명()", returning="변환데이터변수명")
@AfterThrowing(pointcut="참조형 메소드명()", throwing="예외변수명")
@Around("참조형 메소드명()")
@Service //bean 대신 객체 등록
@Aspect //Aspect 등록
public class AroundAdvice {
@Pointcut("execution(* com.naver.service..*service.*(..))")
public void myPointcut() {}
@Around("myPointcut()")
public Object aroundAdvice(ProceedingJoinPoint jp) throws Throwable{
//...생략
}
}
@Service //bean 대신 객체 등록
@Aspect //Aspect 등록
public class AfterReturningAdvice {
@Pointcut("execution(void com.naver.data..*.*(..))")
public void myPointcut() {}
@AfterReturning(pointcut="myPointcut()", returning ="returnObject")
public Object afterReturningAdvice(JoinPoint jp, Object returnObject) throws Throwable{
//...생략
}
}
Reference: