티스토리 뷰
스프링 설정 파일에 <aop:aspectj-autoproxy /> 엘리먼트를 선언하면
스프링 컨테이너가 AOP 관련 어노테이션들을 인식하고 용도에 맞게 처리해준다.
또한 어드바이스 객체들은 설정 파일에 <bean> 등록하거나 @Service 어노테이션을 사용하여 컴포넌트가 스캔될 수 있도록 해야한다.
1. 포인트컷 설정
어노테이션 설정으로 포인트컷을 선언할 때는 @Pointcut을 사용한다. 하나의 어드바이스 클래스 안에 여러 포인트컷을 선언할 수 있으며, 여러 포인트컷을 식별하기 위한 참조 메소드가 이용된다.
참조 메소드란 메소드 몸체가 비어있는 메소드로 단순 포인트컷을 식별하는 이름으로만 사용된다.
다음은 어노테이션 기반의 AOP와 XML 설정 기반의 AOP의 설정 차이이다.
@Service
@Aspect
public class LogAdvice {
/* 포인트컷 식별을 위한 참조 메소드 */
@Pointcut("execution(* com.springbook.biz..*Impl.*(..))")
public void allPointcut() { }
@Pointcut("execution(* com.springbook.biz..*Impl.get*(..))")
public void getPointcut() { }
@Before("allPointcut()")
public void printLog(JoinPoint jp) {
System.out.println("[Common Log] Starting before Business Logic execution...");
}
@AfterReturning("getPointcut()")
public void printAfterLog(JoinPoint jp) {
System.out.println(jp.getSignature().getName());
}
}
<bean id="log" class="com.springbook.biz.LogAdvice"/>
<aop:config>
<aop:pointcut id="allPointcut"
expression="execution(* com.springbook.biz..*Impl.*(..))"/>
<aop:pointcut id="getPointcut"
expression="execution(* com.springbook.biz..*Impl.get.*(..))"/>
<aop:aspect ref="log">
<aop:before pointcut-ref="allPointcut" method="printLog"/>
<aop:after pointcut-ref="getPointcut" method="printAfterLog"/>
</aop:aspect>
</aop:config>
포인트컷과 어드바이스의 결합을 나타내는 애스팩트는 @Aspect를 이용하여 설정한다.
따라서 @Aspect가 설정된 애스팩트 객체에는 반드시 포인트컷과 어드바이스를 결합하는 설정이 있어야 한다.
위 애스팩트 객체에는 포인트컷 메소드(allPointcut())와 어드바이스 메소드(printLog())가 선언되어 있다.
이 두 메소드에 설정된 어노테이션에 의해 위빙이 처리된다.
2. 외부 Pointcut 참조
어드바이스 클래스마다 포인트컷 설정을 하면 반복 선언해야하는 문제점이 발생한다.
포인트컷을 외부에 독립된 클래스에 따로 설정하고,
정의한 클래스 이름과 참조 메소드 이름을 조합하여 지정하여 해결할 수 있다.
독립된 포인트컷 클래스
@Aspect
public class PointcutCommon {
@Pointcut("execution(* com.springbook.biz..*Impl.*(..))")
public void allPointcut() { }
@Pointcut("execution(* com.springbook.biz..*Impl.get*(..))")
public void getPointcut() { }
}
어드바이스 클래스
@Service
@Aspect
public class AfterAdvice {
@After("PointcutCommon.allPointcut()")
public void finallyLog() {
System.out.println("[ After ] 비즈니스 로직 수행 후 무조건 동작");
}
}
@Service
@Aspect
public class AfterReturningAdvice {
@AfterReturning(pointcut="PointcutCommon.getPointcut()", returning="returnObj")
public void afterLog(JoinPoint jp, Object returnObj) {
String methodName = jp.getSignature().getName();
if (returnObj instanceof UserVO) {
UserVO user = (UserVO)returnObj;
if (user.getRole().equals("Admin"))
System.out.println(user.getName() + " 로그인(Admin)");
}
System.out.println("[After Returning] " + "Method Name: " + methodName + ", " + "메소드 리턴값: " + returnObj.toString());
}
}
@Service
@Aspect
public class AroundAdvice {
@Around("PointcutCommon.allPointcut()")
public Object aroundLog(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
System.out.println("[ Around ] Stop Watch Start");
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object obj = pjp.proceed();
stopWatch.stop();
System.out.println("[ Around ] Method Name: " + methodName + ", 수행 시간: " + stopWatch.getTotalTimeMillis() + "ms");
return obj;
}
}
수행 결과
'Spring' 카테고리의 다른 글
07. 스프링 JDBC (0) | 2022.11.13 |
---|---|
06 - 2. 어드바이스 동작 시점, JoinPoint, 바인드 변수 (0) | 2022.11.09 |
06 - 1. Aspect Oriented Programming (0) | 2022.11.09 |
05. 비즈니스 컴포넌트 실습 (0) | 2022.10.31 |
04. 어노테이션 기반 설정 (0) | 2022.10.30 |
댓글