실습 코드 참조
moonhy7/SpringFramework: Spring Framework 실습 코드 정리 (github.com)
3.0절 어드바이스 동작 시점
- 어드바이스는 각 조인포인트에 삽입되어 동작할 횡단 관심에 해당하는 공통 기능
- 동작 시점은 각 AOP 기술마다 다름, 스프링에서는 5가지 동작 시점을 제공
- 어드바이스 메소드의 동작 시점은 <aop:aspect> 엘리먼트 하위에 각각의 엘리먼트를 이용하여 지정함
3.1절 Before 어드바이스
1. Before 어드바이스 구조
- before 어드바이스는 포인트컷으로 지정된 메소드 호출 시 메소드가 실행되기 전에 처리될 내용들을 기술하는데 사용
2. Before 어드바이스 실습 ( _029_BoardWeb_AOP_Before )
1) Before 어드바이스 클래스
- 비즈니스 메소드가 실행되기 전에 수행될 기능을 담은 beforeAdvice() 메소드 선언
package com.springbook.biz.common;
public class BeforeAdvice {
public void beforeAdvice() {
System.out.println("[사전 처리] 비즈니스 로직 수행 전 동작");
}
}
2) 스프링 설정 파일
- <aop:before> 엘리먼트를 사용함
- allPointcut으로 지정한 모든 Impl 클래스의 메소드가 실행되기 직전에 before로 지정한 어드바이스의 beforeAdvice() 메소드가 실행되도록 설정함
<bean id="before" class="com.springbook.biz.common.BeforeAdvice"></bean>
<aop:config>
<aop:pointcut expression="execution(* com.springbook.biz..*Impl.*(..))" id="allPointcut"/>
<aop:pointcut expression="execution(* com.springbook.biz..*Impl.get*(..))" id="getPointcut"/>
<aop:aspect ref="before">
<aop:before pointcut-ref="allPointcut" method="beforeAdvice"/>
</aop:aspect>
</aop:config>
3) 실행 결과
- before 형태로 메소드가 동작하는 것을 알 수 있음
3.2절 After Returning 어드바이스
1. After Returning 어드바이스 구조
- After Returning 어드바이스는 포인트컷으로 지정된 메소드가 정상적으로 실행되고 나서 메소드 수행 결과로 생성된 데이터를 리턴하는 시점에 동작함
- 비즈니스 메소드 수행 결과로 얻은 결과 데이터를 이용하여 사후 처리 로직을 추가할 때 사용
2. After Returning 어드바이스 실습 ( _030_BoardWeb_AOP_AfterReturning )
1) After Returning 어드바이스 클래스
package com.springbook.biz.common;
public class AfterReturningAdvice {
public void afterReturningAdvice() {
System.out.println("[사후 처리] 비즈니스 로직 수행 후 동작");
}
}
2) 스프링 설정 파일
- <aop:afterReturning> 엘리먼트를 사용함
- Impl로 끝나는 모든 메소드가 실행되기 이후에 afterReturning로 지정한 afterReturningAdvice() 메소드가 실행되도록 설정함
<bean id="afterReturning" class="com.springbook.biz.common.AfterReturningAdvice"></bean>
<aop:aspect ref="afterReturning">
<!-- 어드바이스 동작 시점 : aop:before, aop:after, aop:arround...
aop:before : 포인트컷 메소드가 실행되기 전에 동작
aop:after-returning : 포인트컷 메소드가 정상적으로 리턴되면 동작(try에 해당)
aop:after-throwing : 포인트컷 메소드 실행중에 예외가 발생하면 동작(catch에 해당)
aop:after : 포인트컷 메소드가 완료된후 무조건 실행(finally에 해당)
aop:arround : 포인트컷 메소드 호출을 가로채서 포인트컷 실행 전후에 처리할 어드바이스 삽입-->
<aop:after-returning pointcut-ref="getPointcut" method="afterReturningAdvice"/>
3) 실행 결과
3.3절 After Throwing 어드바이스
1. After Throwing 어드바이스 구조
- After Throwing 어드바이스는 포인트컷으로 지정한 메소드가 실행되다가 예외가 발생하는 시점에 동작함
- 따라서 예외 처리 어드바이스를 설정할 때 사용
2. After Throwing 어드바이스 테스트 ( _031_BoardWeb_AOP_AfterThrowing )
1) 어드바이스 클래스 구현
- 예외 처리 기능을 가진 어드바이스 클래스
package com.springbook.biz.common;
public class AfterThrowingAdvice {
public void afterThrowingAdvice() {
System.out.println("[예외 처리] 비즈니스 로직 처리 중 예외 발생");
}
}
2) 스프링 설정 추가
- 예외 발생 시, 예외 처리 어드바이스가 동작할 수 있도록 스프링 설정 추가
- afterThrowing 어드바이스의 exceptionLog() 메소드를 실행하기 위해 allPointcut으로 포인트컷 지정
<bean id="afterThrowing" class="com.springbook.biz.common.AfterThrowingAdvice"></bean>
<aop:aspect ref="afterThrowing">
<aop:after-throwing pointcut-ref="allPointcut" method="afterThrowingAdvice"/>
</aop:aspect>
3) 예외 코드 추가
- After Throwing 어드바이스는 비즈니스 메소드에서 예외가 발생할 때만 동작하므로 예외 코드 추가
- 글 등록 작업에서 서브쿼리를 사용하여 SEQ 컬럼값을 자동으로 증가시켜서 0부터 시작이된다.
- 예외 처리 테스트를 위해서 seq 변수값이 0이면 IllegalArgumentException을 강제로 발생시킴
public void insertBoard(BoardVO vo) {
//객체 생성 시에 필드 변수의 int 타입들은 0으로 초기화 됨
if(vo.getSeq() == 0) {
throw new IllegalArgumentException("0번 글은 등록할 수 없습니다.");
}
boardDAO.insertBoard(vo);
}
4) 실행 결과
- afterThrowingAdvice() 메소드 수행됨
3.4절 After 어드바이스
1. After 어드바이스 구조
- try-catch-finally 구문에서 finally 블록처럼 예외 발생 여부에 상관없이 무조건 수행되는 어드바이스를 등록할 때 After 어드바이스를 사용
2. After 어드바이스 테스트 ( _032_BoardWeb_AOP_After )
1) 어드바이스 클래스 구현
- 예외 처리 기능의 어드바이스 클래스 구현
package com.springbook.biz.common;
public class AfterAdvice {
public void afterAdvice() {
System.out.println("[사후 처리] 비즈니스 로직 수행 후 무조건 동작");
}
}
2) 스프링 설정에 따른 각 실행 결과
- 예외가 발생한 상황에서도 afterAdvice() 메소드가 먼저 실행되고 afterThrowingAdvice() 메소드가 그 다음에 실행됨
<bean id="afterThrowing" class="com.springbook.biz.common.AfterThrowingAdvice"></bean>
<bean id="after" class="com.springbook.biz.common.AfterAdvice"></bean>
<aop:config>
<aop:aspect ref="afterThrowing">
<aop:after-throwing pointcut-ref="allPointcut" method="afterThrowingAdvice"/>
</aop:aspect>
<aop:aspect ref="after">
<aop:after pointcut="allpointcut" method="afterAdvice"/>
</aop:aspect>
</aop:config>
- 예외가 발생하지 않을 땐 각 비즈니스 메소드 실행 후 afterAdvice() 메소드가 실행됨
<bean id="afterThrowing" class="com.springbook.biz.common.AfterThrowingAdvice"></bean>
<bean id="after" class="com.springbook.biz.common.AfterAdvice"></bean>
<aop:config>
<aop:aspect ref="afterReturning">
<aop:after-returning pointcut-ref="allPointcut" method="afterReturningAdvice"/>
</aop:aspect>
<aop:aspect ref="after">
<aop:after pointcut="allpointcut" method="afterAdvice"/>
</aop:aspect>
</aop:config>
3.5절 Around 어드바이스
- 하나의 어드바이스가 비즈니스 메소드 실행 전과 후에 모두 동작하여 로직을 처리하는 경우 Around 어드바이스 사용
1. Around 어드바이스 구조
- Around 어드바이스는 하나의 어드바이스가 비즈니스 메소드 실행 전과 후에 모두 동작하여 로직을 처리하는 경우에 사용
2. Around 어드바이스 테스트 ( _033_BoardWeb_AOP_Around )
1) 어드바이스 클래스 구현
- Around 어드바이스는 클라이언트의 메소드 호출을 가로챈다.
- 따라서 클라이언트가 호출한 비즈니스 메소드가 실행되기 전에 사전 처리 로직을 수행 (php.proceed() 메소드 호출 앞에 작성된 코드는 Before 어드바이스와 동일하게 동작)
- 비즈니스 메소드가 모두 실행되고 나서 사후 처리 로직을 수행할 수 있음 (php.proceed() 메소드 호출 뒤에 작성된 코드는 After 어드바이스와 동일하게 동작)
- ProceedingJoinPoint 객체를 매개변수로 받아 proceed() 메소드를 통해서 비즈니스 메소드를 호출함
package com.springbook.biz.common;
import org.aspectj.lang.ProceedingJoinPoint;
public class AroundAdvice {
//ProceedingJoinPoint : 지금 실행중인 포인트컷 메소드, JoinPoint 인터페이스를 상속받아서 구현한 객체
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("[BEFORE] : 비즈니스 로직 수행 전 처리할 내용...");
Object returnObj = pjp.proceed();
System.out.println("[AFTER] : 비즈니스 로직 수행 후 처리할 내용...");
return returnObj;
}
}
2) 스프링 설정 추가
<bean id="afterThrowing" class="com.springbook.biz.common.AfterThrowingAdvice"></bean>
<bean id="around" class="com.springbook.biz.common.AroundAdvice"></bean>
<aop:config>
<aop:aspect ref="around">
<aop:around pointcut-ref="allPointcut" method="aroundAdvice"/>
</aop:aspect>
</aop:config>
3) 실행 결과
댓글