상황
핵심 로직 클래스인 MessageImpl class의 sayHi() 메소드가 실행되기 전과 이후에 어떤 모듈을 실행해야만 한다. AOP를 이용하여 처리한다.
Proxy를 통한 간접 접근
스프링 설정파일을 보면 bean태그가 id="hiAdvisor" 인 놈이 있다.
org.springframework.aop.support.DefaultPointcutAdvisor 클래스의 객체를 생성한 것인데 property로 advice와 pointcut을 가지고 있다.
예제에서 설정파일을 보면 property태그의 name이 advice와, pointcut 인 놈들을 property로 가지고 있는데
name이 advice인 놈에게는 실행할 모듈을 지정해 놓고(무엇을 할지 : 예제에서는 LoggingAdvice class가 되겠다.)
name이 pointcut인 놈에게는 어떤 메소드가 실행 될 때 실행할지 지정해 놓는다.(언제 : 예제에서는 sayHi 메소드가 되겠다.)
더 자세한 설명을 하자면 아래와 같다.
** spring aop 라이브러리가 필요하다.(아래는 maven 설정 할때)
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
1.
스프링에서 제공하는 org.springframework.aop.framework.ProxyFactoryBean 클래스의 객체를 생성(예제에서는 proxy라는 id로 생성)하고 property로 target과 interceptorNames를 준다.
target은 sayHi 메소드가 담긴 클래스가 될것이고 interceptorNames는 Advisor가 된다.
Advisor 는 아래의 설명을 따라가자.
<!-- Proxy를 통한 간접 접근 -->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="targetBean"/> <!-- local은 현재 설정파일, bean은 전체 설정파일 -->
</property>
<property name="interceptorNames">
<list>
<value>hiAdvisor</value> <!-- Advisor 기술 -->
</list>
</property>
</bean>
2.
Advisor(쉽게 말해 무엇을 언제 할지 정하기)를 사용하기 위해서는 스프링에서 제공하는 org.springframework.aop.support.DefaultPointcutAdvisor 클래스를 사용해야 한다.
(예제 에서는 <bean id="hiAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> 로 객체를 생성함)
3.
pointcut property 태그 부분에 클래스를 아래와 같이 지정해 주고 패턴은 표현식을 이용하여 패턴을 정의한다.(패턴은 구글링하기를 권장)
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern">
<value>.*say*(..)</value> <!-- 정의된 패턴값과 일치되는 메소드가 실행될 경우 AOP 발동 -->
</property>
</bean>
4.
advice에서 지정한 클래스는 MethodInterceptor를 구현(Implement)하고 invoke 메소드를 재정의 하면 된다.
invoke 메소드는 MethodInvocation 타입의 변수를 인자로 가지고 있는데
그 변수로 아래와 같이 원래 실행하려 했던 메소드를 실행할 수 있다.
Object object = invocation.proceed();
invocation이 MethodInvocation 타입의 변수라는 것을 참고하자.
위의 문장이 기준이 된다.
이 문장보다 먼저 실행되는 명령은 선처리가 될 것이고
이 문장보다 나중에 실행되는 명령은 후처리가 될 것이다.
아래의 에제에서 LoggingAdvice class를 보면 이해 할 수 있을 것이다.
============================================================================================================================================
스프링 설정 파일
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<!-- Target -->
<bean id="targetBean" class="pack.MessageImpl">
<property name="name" value="한국인"/>
</bean>
<!-- Proxy를 통한 간접 접근 -->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref local="targetBean"/> <!-- local은 현재 설정파일, bean은 전체 설정파일 -->
</property>
<property name="interceptorNames">
<list>
<value>hiAdvisor</value> <!-- Advisor 기술 -->
</list>
</property>
</bean>
<!-- Advice(Aspect) : Target으로 weaving -->
<bean id="loggingAdvice" class="advice.LoggingAdvice"/>
<!-- Advisor(Advice + pointcut) -->
<bean id="hiAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice">
<ref local="loggingAdvice"/>
</property>
<property name="pointcut">
<bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern">
<value>.*say*(..)</value>
</property>
</bean>
</property>
</bean>
<!--
logginAdvice 안에는 MethodInterceptor 가 구현되어있고 invoke 메소드가 재정의 되어있다.
재정의된 메소드 invoke가 pointcut에 지정된 메소드가 실행됬을때 반응하여 실행되는 것이다.
-->
</beans>
============================================================================================================================================
MethodInterceptor 구현한 Advice class
package advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class LoggingAdvice implements MethodInterceptor{
//MethodInterceptor는 Around Advice를 지원
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//핵심 로직 전에 수행
String methodName = invocation.getMethod().getName(); // target 메소드 명 얻기
System.out.println("호출될 메소드 이름 : " + methodName);
Object object = invocation.proceed(); //핵심 로직 수행 - sayHi();
//핵심 로직 후에 수행
System.out.println(methodName + "핵심 로직 수행 후 마무리 작업 수행 ");
return object;
}
}
============================================================================================================================================
핵심 로직 클래스
package pack;
//핵심 로직 클래스 - Target Class
public class MessageImpl implements MessageInter {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public void sayHi() {
System.out.println(name + "님! 비즈니스 로직 처리 중");
//시간 끌기
int t = 0;
while(t < 5){
try {
Thread.sleep(1000);
System.out.print(".");
t++;
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("sayHi 처리 완료");
}
}
============================================================================================================================================
Interface
package pack;
public interface MessageInter {
void sayHi(); // AOP가 적용될 메소드
}
============================================================================================================================================
메인 클래스
package pack;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("initaop.xml");
MessageInter inter = (MessageInter)context.getBean("proxy");
inter.sayHi();
}
}
'spring > AOP' 카테고리의 다른 글
AOP 구현하는 방법3 : 어노테이션을 이용한 방법 (0) | 2014.05.07 |
---|---|
AOP 구현하는 방법2 : aop namespace를 이용한 방법 (0) | 2014.05.07 |
AOP 용어 (0) | 2014.05.07 |
AOP 구조를 이해하는 예제3(어노테이션을 이용한 예제) (0) | 2013.08.09 |
AOP 구조를 이해하는 예제2(MethodInterceptor) (0) | 2013.08.09 |