스프링에서는 4가지 보조 업무가 존재한다.
Before Advice: 앞에만 필요한 경우
After returnning Advice: 뒤에만 필요한 경우
After throwing Advice: 예외를 처리하는 경우
Around Advice: 앞뒤 둘다 필요한 경우
<자바 코드>
public class Program {
public static void main(string[] args) {
Exam exam = new NewlecExam(1,1,1,1);
Exam proxy = (Exam)Proxy.newProxyInstance(newlecExam.class,
new Class[] {Exam.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
long start = System.curretTimeMillis();
// method는 실제 업무를 실행할 수 있는 메서드 호출 가능
// invoke를 사용하여 실제 업무 객체를 넣어준다 (exam)
// 두 번째 인자 args : exam안에 여러 메서드를 넣을 수 있음.
// invoke는 Object 형으로, 모든 형태를 반환 가능
Object result = method.invoke(exam, args);
long end = System.curretTimeMillis();
String message = (end-start) + "ms";
System.out.println(message);
return result;
}
System.out.printf("total is %d\n", proxy.total());
System.out.printf("total is %d\n", proxy.avg());
}
}
xml 방식으로 구현해보기
...
<bean id="target" class="spring.di.entity.NewlecExam" p:kor="1" p:eng="1" p:math="1" p:com="1"/>
<bean id="logAroundAdvice" class="spring.aop.LogAroundAdvice" />
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="target" />
<property name="interceptorNames">
<list>
<value>logAroundAdvice</value>
</list>
</property>
</bean>
setting.xml
1. 4개의 값을 초기화하는 작업
2. 프락시라는 객체 생성
프락시에는 2가지 코드가 있어야함.
실제 target에 해당하는 classloader, 곁다리 업무
-> 프로퍼티로 설정
참조면 ref, value 값인 경우 val로 설정
NewlecExam이 참조이니까 ref에 target을 설정
핸들러를 넣어줘야 함 (interceptorNames를 setter로 해서 설정)
list의 경우는 참조열이기 때문에 value는 참조하는 영역에 이름을 넣어줘야 함
LogAroundAdvice.class
MethodInterceptor 인터페이스를 구현해야 함.
public class LogAroundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long start = System.currentTimeMillis();
Object result = invocation.proceed();
long end = System.currentTimeMillis();
String message = (end - start) + "ms 시간이 걸렸습니다.";
System.out.println(message);
return result;
}
}
Program.class
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.println("avg is %d\n " + proxy.avg());
}
}
Program에서는 프락시가 필요함.
getBean을 통해서 프락시 값을 꺼내와야 함.
BeforeAdvice
...
<bean id="target" class="spring.di.entity.NewlecExam" p:kor="1" p:eng="1" p:math="1" p:com="1"/>
<bean id="logAroundAdvice" class="spring.aop.LogAroundAdvice" />
<bean id="logBeforeAdvice" class="spring.aop.LogBeforeAdvice" />
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="target" />
<property name="interceptorNames">
<list>
<value>logAroundAdvice</value>
<value>logBeforeAdvice</value>
</list>
</property>
</bean>
public class LogBeforeAdvice implements MethodBeforeAdvice
{
@Override
// 현재 호출되고 있는 함수의 이름, 파라미터 얻고 싶으면 method, args 이용
// arget에 대한 객체를 얻고 싶다면 target 설정
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("LogBeforeAdvice.before");
}
}
-> before가 출력되고, target에 대한 메서드가 실행된다.
AfterReturning
afterReturning의 경우, 함수가 호출된 이후 반환값을 갖게 되면 returnValue 사용
public class LogAfterReturningAdvice implements AfterReturningAdvice
{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) {
System.out.println("returnvalue:" + returnValue + "method:"+method.getName());
}
}
-> target의 메서드가 실행되고 returnvalue 출력
예외가 발생했을때 무엇을 실행시키고 싶은 경우 AfterThrowingAdvice
public class LogAfterThrowingAdvice implements ThrowAdvice
{
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("예외가 발생하였습니다.: " + e.getMessage());
}
}
구현해야 하는 afterThrowing 메서드에는 감지할 특정 예외를 넣어주면 된다.
target인 newLecExam.class의 total() 메서드의 특정 예외가 있는 경우
...
// newLecExam.class
@Override
public int total() {
int result = kor+eng+math+com;
if(kor > 100)
throw new IllegalArgumentException("유효하지 않은 국어점수");
...
proxy.total()을 실행시키면 예외가 발생하고, 예외 발생 시점에 메시지를 출력가능
'💻 Backend > 스프링' 카테고리의 다른 글
Webflux와 R2DBC (0) | 2024.09.05 |
---|---|
[Spring Security] 스프링 시큐리티 용어 및 구조 (0) | 2022.04.11 |
자바 AOP 예제 정리 - 순수 자바로 AOP 구현해보기 (0) | 2022.03.22 |
스프링 AOP 정리 - 스프링 핵심 원리 - 고급편 (0) | 2022.03.22 |
ApplicationContext 정리 - 스프링 핵심원리 기본편 (0) | 2022.03.14 |