Advice 동작 시점 설명
Before 비지니스 메서드 실행 전 동작
After - AfterReturning : 비지니스 메서드가 성공적으로 리턴되면 동작
- AfterThrowing : 비지니스 메서드 실행 중 예외가 발생하면 동작(마치 try~catch 블록에서 catch 블록에 해당)
- After : 비지니스 메서드가 실행된 후, 무조건 실행(try~catch~finally 블록에서 finally 블록에 해당)
Around Around는 메서드 호출 자체를 가로채 비지니스 메서드 실행 전후에 처리할 로직을 삽입할 수 있음

 

// 예외를 발생시키기 위해 NewlecExam 클래스 수정
package spring.aop.entity;

public class NewlecExam implements Exam {
	
	private int kor;
	private int eng;
	private int math;
	private int com;
	
	public NewlecExam() {
		
	}
	
	public NewlecExam(int kor, int eng, int math, int com) {
		this.kor = kor;
		this.eng = eng;
		this.math = math;
		this.com = com;
	}

	@Override
	public int total() {
		
		int result = kor+eng+math+com;
		
		// AfterThrowingAdvice 테스트를 위해 추가 
		// 예외를 시키기 위한 if문
		if(kor > 100) // 점수가 100점을 넘을 수 없음
			throw new IllegalArgumentException("유효하지 않은 국어점수");
		
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		return result;
	}

	@Override
	public float avg() {
		float result = total() / 4.0f;
		return result;
	}

	@Override
	public String toString() {
		return "NewlecExam [kor=" + kor + ", eng=" + eng + ", math=" + math + ", com=" + com + "]";
	}
	
}

 

// ThrowsAdvice를 구현한 LogAfterThrowingAdvice 클래스

package spring.aop.advice;

import org.springframework.aop.ThrowsAdvice;

public class LogAfterThrowingAdvice implements ThrowsAdvice{
	//public void afterThrowing(? e) throws Throwable{}
	public void afterThrowing(IllegalArgumentException e) throws Throwable{
		System.out.println("예외가 발생하였습니다.: " + e.getMessage());
	}
}

 

// setting.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util-3.0.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.0.xsd">
	
	
	<bean id="target" class="spring.aop.entity.NewlecExam" p:kor="101" p:eng="1" p:com="1" p:math="1"/> // p:kor="1"에서 p:kor="101"으로 변경
	<bean id="logAroundAdvice" class="spring.aop.advice.LogAroundAdvice"/>
	<bean id="logBeforeAdvice" class="spring.aop.advice.LogBeforeAdvice"/>
	<bean id="logAfterReturningAdvice" class="spring.aop.advice.LogAfterReturningAdvice"/>
	<bean id="logAfterThrowingAdvice" class="spring.aop.advice.LogAfterThrowingAdvice"/> // 추가
	<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="target" />
		<property name="interceptorNames">
			<list>
				<value>logAroundAdvice</value>
				<value>logBeforeAdvice</value>
				<value>logAfterReturningAdvice</value>
				<value>logAfterThrowingAdvice</value> // 추가
			</list>
		</property>
	</bean>

</beans>

 

// main 메서드

package spring.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import spring.aop.entity.Exam;
import spring.aop.entity.NewlecExam;

public class Program {

	public static void main(String[] args) {
		
		ApplicationContext context = new ClassPathXmlApplicationContext("spring/aop/setting.xml"); //추가
		
		Exam proxy = (Exam) context.getBean("proxy");
		
		System.out.printf("total is %d\n", proxy.total());
		System.out.printf("avg is %f\n", proxy.avg());
						
	}

}

// <출력>
//앞에서 실행될 로직
//예외가 발생하였습니다.: 유효하지 않은 국어점수
//Exception in thread "main" java.lang.IllegalArgumentException: 유효하지 않은 국어점수
//	at spring.aop.entity.NewlecExam.total(NewlecExam.java:63)
//	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
//	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
//	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
//	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
//	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
//	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
//	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
//	at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:112)
//	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
//	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:55)
//	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
//	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
//	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
//	at spring.aop.advice.LogAroundAdvice.invoke(LogAroundAdvice.java:14)
//	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
//	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
//	at com.sun.proxy.$Proxy5.total(Unknown Source)
//	at spring.aop.Program.main(Program.java:21)

 

참고자료

[1] 유튜브 채널 뉴렉처 - After Returning / Throwing 어드바이스 구현하기

Developer Quarterly