이전 강의에서는 JAVA 코드로 AOP를 구현했었는데, 이번엔 스프링으로 AOP를 구현해보겠다.
1. 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context">
<!-- 스프링에서는 모든 설정을 setting xml에서 처리함 -->
<bean id="target" class="spring.aop.entity.NewlecExam" p:kor="1" p:eng="1" p:math="1" p:com="1"/>
<bean id="logAroundAdvice" class="spring.aop.advice.LogAroundAdvice"/>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 앞의 target은 setTarget을 의미, 뒤 ref의 target은 위의 target빈을 의미 -->
<!-- 프록시에서 인터페이스는 스프링이 자동으로 처리해주기 때문에 target이랑 핸들러(interceptorNAmes란 이름으로)만 주입해주면된다. -->
<property name="target" ref="target"/>
<property name="interceptorNames">
<list>
<value>logAroundAdvice</value>
</list>
</property>
</bean>
</beans>
스프링에서는 자동으로 인터페이스를 지정해주기 때문에 사용할 객체와 핸들러만 DI 해주면 된다.
여기서 핸들러를 설정할 때, property name으로 interceptorNames를 사용한다.
2. 핸들러 클래스 생성
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;
}
}
위 클래스는 스프링에서 사용할 프록시용 핸들러이다.
JAVA 로 AOP를 구현했을 때는 method.invoke(객체,파라미터);를 사용하였지만
스프링에서 핸들러를 구현할 때는 invocation.proceed() 메소드를 사용하여 주 기능을 수행한다.
3. 코드 실행
public class NewlecExam implements Exam{
...
@Override
public int total() {
int result = kor+eng+math+com;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
@Override
public float avg() {
float result=total()/4.0f;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}
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());
}
}
프록시가 적용되어 NewlecExam의 totla, avg 메소드에서의 주기능뿐만아니라 핸들러의 부가적인 코드들도 수행되었음을 확인할 수 있다.