2015년 4월 13일 월요일

SpringFramework - AOP 개념 이해하기

AOP는 주 로직이 아닌 보안, 한글 처리 등의 공통업무를
    주 메인 페이지에서 매번 불러오거나 하는등의 번잡함을
    피하기 위해 제공됨
    이 를 적용하면 클래스, 화면 시작시 무조건 AOP
     를 거치고 나서 진행되는등의 업무를 구현 할 수 있다.

AOP는 크게 컴파일시, 클래스 로드시, 런타임으로 실행되는
    방식에 따라 구분되는데 Springframework 의 경우에는
    가장 후자인 런타임 방식으로 프록시를 이용하여
    AOP를 제공하고 있다.

Advice 등록방법
(1) bin에 jar 파일 등록
(2) advice 클래스를 구현(advice중 interface를 상속받아서 작성)
(3) bean 등록 및 해당 bean을 <aop:config> 등록

(3-2) 아래 4번 이하 예제처럼 advice를 해줄수 있는
     jar 파일을 bean 선언하는 방법
...... (advice할수 있는 방법이 많다....)

1. AOP 화 할 기능을 정의
    (메인 로직 앞뒤 시간체크 및 소요시간 출력 로직 삽입)
    이를 구현하는 클래스 를 작성해봄
    우선 해당 로직이 들어가는 클래스를 작성
     (여기에는 계산 + 시간 체크, 소요시간 체크가 합쳐짐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StopWatch;
public class Calc {
   public int Add(int x, int y){
      //AOP
      Log log = LogFactory.getLog(this.getClass());
      StopWatch sw = new StopWatch();
      sw.start();
      log.info("add시작");
      int result = x+y;
      sw.stop();
      log.info("add끝");
      log.info("[TimeLOG] Method : Add");
      log.info("[TimeLOG] process Time : " + sw.getTotalTimeMillis());
      return result;
   }
   public int Mul(int x, int y){
      Log log = LogFactory.getLog(this.getClass());
      StopWatch sw = new StopWatch();
      sw.start();
      log.info("mul시작");
      int result = x*y;
      sw.stop();
      log.info("mul끝");
      log.info("[TimeLOG] Method : Mul");
      log.info("[TimeLOG] process Time : " + sw.getTotalTimeMillis());
      return result;
   }
}


1
2
3
4
5
6
7
public class Program {
   public static void main(String[] args) {
      Calc c = new Calc();
      System.out.println(c.Add(1230, 3220));
      System.out.println(c.Mul(10, 2000)); 
   }
}


------------------------------------------------결과값 
12월 26, 2013 3:46:12 오후 Calc Add
정보: add시작
12월 26, 2013 3:46:12 오후 Calc Add
정보: add끝
12월 26, 2013 3:46:12 오후 Calc Add
정보: [TimeLOG] Method : Add
12월 26, 2013 3:46:12 오후 Calc Add
정보: [TimeLOG] process Time : 41
4450
12월 26, 2013 3:46:12 오후 Calc Mul
정보: mul시작
12월 26, 2013 3:46:12 오후 Calc Mul
정보: mul끝
12월 26, 2013 3:46:12 오후 Calc Mul
정보: [TimeLOG] Method : Mul
12월 26, 2013 3:46:12 오후 Calc Mul
정보: [TimeLOG] process Time : 0
20000
------------------------------------------------결과값 

2. 1번에서 새로 패키지를 하나 생성
    (편의상 AOP라고 정의)
      Calc 를 인터페이스화 하고 해당 인터페이스를 
      임플리먼트한 클래스를 하나 따로 생성 NewCalc.java
      그리고 메인과 Clac 사이에 LogPrintHandler.java 로 핸들러 하나를 둔다.
      이 핸들러는 InvocationHandler 를 임플리먼트해 구현하기로 한다.
    이 예제에서는 SpringFramework에서 지원하는 AOP를 만약 자바에서 같은
      형태로 지원하고자 할대 내용에 대해 기술하고 있음

1
2
3
4
5
6
package AOP;
public interface Calc {
   int ADD(int x, int y);
   int MUL(int x, int y);
   int SUB(int x, int y);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package AOP;
public class NewCalc implements Calc {
   @Override
   public int ADD(int x, int y) {
      int sum = x + y;
      return sum;
   }
   @Override
   public int MUL(int x, int y) {
      int mul = x * y;
      return mul;
   }
   @Override
   public int SUB(int x, int y) {
      int sub = x -y;
      return sub;
   }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package AOP;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StopWatch;
public class LogPrintHandler implements InvocationHandler{
   private Object target;
   public LogPrintHandler(Object target){
      this.target = target;
   }
   @Override
   public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
      System.out.println("Invoke Method Start....");
   //Cross cuttion conson - 보조 업무 구현 진행시작
      Log log = LogFactory.getLog(this.getClass());
      StopWatch sw = new StopWatch();
      sw.start();
      log.info("타이머 시작"); 
   //Main conson call
      int result = (int)method.invoke(target, args);
      sw.stop();
      log.info("타이머 정지");
      log.info("[TimeLOG] Method : " + method.getName());
      log.info("[TimeLOG] process Time : " + sw.getTotalTimeMillis());
      return result;
   }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package AOP;
import java.lang.reflect.Proxy;
public class CalcMain {
   public static void main(String[] args) {
      Calc cal = new NewCalc();
      Calc proxy =(Calc)Proxy.newProxyInstance
             (cal.getClass().getClassLoader(),//loader : find class (클래스 찾기)
              cal.getClass().getInterfaces(),  //interfaces : find action (행위찾기)
              new LogPrintHandler(cal)); //handler : 보조업무 구현
      //normal run -- no proxy
      //System.out.println(cal.ADD(100, 200));
      //than proxy 적용하고자 하면?
      System.out.println(proxy.ADD(50, 1000));
      System.out.println(proxy.MUL(20, 40));
   } 
}

------------------------------------------------결과값 
Invoke Method Start....
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: 타이머 시작
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: 타이머 정지
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: [TimeLOG] Method : ADD
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: [TimeLOG] process Time : 28
1050
Invoke Method Start....
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: 타이머 시작
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: 타이머 정지
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: [TimeLOG] Method : MUL
12월 26, 2013 3:55:58 오후 AOP.LogPrintHandler invoke
정보: [TimeLOG] process Time : 0
800
------------------------------------------------결과값 

3. AOP에서 지원하는 Advice 중에 Around 기능을 구현
    편의상 패키지 네임을 AOP2 라고 정하기로 하고
      기본적인 SpringFrameWork 의 jar 파일들을 읽어들이도록 함
      읽어들이는 방법은 생으로 jar 파일을 찾아서 등록하는 방법
      maven 을 이용하는 방법, 
      spring에서 지원하는 방법등 여러가지 가 있지만
   여기서는 생으로 읽어들이는 방법을 진행하기로 함

   우선 spring 파일을 다운로드 받아서 압축을 풀어둠 
     혹시 모른다면 밑의 링크에서 마음에 맞는 버전으로 선택하고
     보통 한국에서 많이 쓰는건 3.0 점대 파일들을 쓰고 
     여기서는 3.0.2 기준으로 설명합니다.
   세부 내용을 잔잔이 보면 with docs 라고 하는거와 
    dependency 버전이 있는데
   두개가 좀 틀리니 둘다 받아두세요
   기본이 with docs 이고, dependency 는 확장 버전입니다.

   이중 여기 예제를 무난하게 하는데에 있어서는
     아래 내용정도는 포함되어야 함
    (아래 내용이 해당 프로젝트 Web-content-WEB-INF-bin 폴더안에 복사되어 있어야 함)
    이중 core, aop, context, beans, asm, expression 은 기본 패키지 
      내 dist 내부에 위치하고 있고
      다른 내용들은 dependency  밑에
      org.aopalliance\com.springsource.org.aopalliance\1.0.0 
      이 폴더 밑에 위치함

   jar 파일들이 추가되었다면 우선 자바 파일부터 진행 하겠음
     패키지 추가 (편의상 AOP2 라고 칭하겠음)
   해당 패키지 밑에 기존에 AOP에 작성한 Calc.java, NewCalc.java 
     파일을 복사해서 넣어둠
   XML 에 연동할 클래스 LogPrintAroundAdvice.java 를 생성및 
     아래와 같이 작성함

LogPrintAroundAdvice.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package AOP2;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StopWatch;
public class LogPrintAroundAdvice implements  MethodInterceptor{
   @Override
   public Object invoke(MethodInvocation method) throws Throwable {
      System.out.println("Invoke Method Start");
      Log log = LogFactory.getLog(this.getClass());
      StopWatch sw = new StopWatch();
      sw.start();
      log.info("타이머 시작"); 
   //Main conson call
      Object result = method.proceed();
   //////////////////
      sw.stop();
      log.info("타이머 정지");
      log.info("[TimeLOG] Method : " + method.getMethod());
      log.info("[TimeLOG] process Time : " + sw.getTotalTimeMillis());
      return result;
   }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package AOP2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CalcMain {
   public static void main(String[] args) {
//기존에 작성했던 AOP의 자바코드에서의 구현 코드들   
//normal AOP 구현
   // 일반적인 AOP 구현
//Calc cal = new NewCalc();
//      Calc proxy =(Calc)Proxy.newProxyInstance(
//      cal.getClass().getClassLoader(),//loader : find class (클래스 찾기)
//      cal.getClass().getInterfaces(),  //interfaces : find action (행위찾기)
//      new LogPrintHandler(cal)); //handler : 보조업무 구현  
//      //normal run -- no proxy
//      //System.out.println(cal.ADD(100, 200));
//      //than proxy 적용하고자 하면?
//      System.out.println(proxy.ADD(50, 1000)); 
//      System.out.println(proxy.MUL(20, 40));
   //base Spring setting --> proxy run
   //스프링 기반 셋팅으로 프록시를 처리
   //Proxy 만들고 객체를 넘기고 필요한 객체를 생성하는 작업은 xml 설정파일을 통해 설정됨
      ApplicationContext con=new ClassPathXmlApplicationContext("ApplicationContext.xml");
      Calc proxy = (Calc)con.getBean("proxy");
      System.out.println(proxy.ADD(500, 300));
      System.out.println(proxy.MUL(500, 300));
   } 
}

src 밑에 새로 xml 형식의 파일 하나를 만들어 이름을 ApplicationContext.xml 로 한뒤
   다음과 같이 작성함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
   <bean id="cal" class="AOP2.NewCalc">
   </bean>
   <bean id ="logPrintAroundAdvice" class="AOP2.LogPrintAroundAdvice"></bean>
   <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <list>
            <value>AOP2.Calc</value>
         </list>
      </property>
      <property name="target" ref="cal">
      </property>
      <property name="interceptorNames">
         <list>
            <value>logPrintAroundAdvice</value>
         </list>
      </property>
   </bean>
</beans>

------------------------------------------------결과값 
12월 26, 2013 4:32:34 오후 org.springframework.context.support.AbstractApplicationContext prepareRefresh
정보: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@40c19080: startup date [Thu Dec 26 16:32:34 KST 2013]; root of context hierarchy
12월 26, 2013 4:32:34 오후 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
정보: Loading XML bean definitions from class path resource [ApplicationContext.xml]
12월 26, 2013 4:32:34 오후 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
정보: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5b43c919: defining beans [cal,logPrintAroundAdvice,proxy]; root of factory hierarchy
Invoke Method Start
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: 타이머 시작
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: 타이머 정지
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: [TimeLOG] Method : public abstract int AOP2.Calc.ADD(int,int)
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: [TimeLOG] process Time : 1
800
Invoke Method Start
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: 타이머 시작
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: 타이머 정지
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: [TimeLOG] Method : public abstract int AOP2.Calc.MUL(int,int)
12월 26, 2013 4:32:35 오후 AOP2.LogPrintAroundAdvice invoke
정보: [TimeLOG] process Time : 1
150000
------------------------------------------------결과값 

4. 이번엔 마찬가지로 SpringFramework에서 제공하는 advise 
    중에서 제공하는 기능중에서 Before에서 알아보려고 함
    패키지 새로 작성하고 (편의상 이름은 AOP3 이라고 칭함)
    여기에 AOP2에서 작성했던 
    Calc.java, CalcMain.java, NewClac.java 세개 파일을 복사해둠
    Before 기능을 이용하기위해서 클래스 파일 하나를 작성
      함 LogPrintBeforeAdvice.java
      해당 클래스는 MethodBeforeAdvice 라는 
      SpringFramework 에서 제공하는 인터페이스를 적용함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package AOP3;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;
public class LogPrintBeforeAdvice implements MethodBeforeAdvice {
//Advice 중에서 이전 적용 되는 인터페이스 : MethodBeforeAdvice
   @Override
   public void before(Method method, Object[] args, Object target)
         throws Throwable {
      System.out.println("Before Method Start");
      Log log = LogFactory.getLog(this.getClass());
   //StopWatch sw = new StopWatch();
   //sw.start();
      log.info("[Method Before ]: 이전 보조 업무 시작 ");
   }
}

그리고 xml 설정 파일에 해당 클래스를 등록시키면 됨

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="UTF-8"?>
   <bean id="cal" class="AOP3.NewCalc"></bean>
   <bean id ="logPrintbeforeAdvice" class="AOP3.LogPrintBeforeAdvice"></bean>
   <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <list>
            <value>AOP3.Calc</value>
         </list>
      </property>
      <property name="target" ref="cal"></property>
      <property name="interceptorNames">
         <list>
            <value>logPrintbeforeAdvice</value>
         </list>
      </property>
   </bean>
</beans>

------------------------------------------------결과값 
12월 26, 2013 4:34:58 오후 org.springframework.context.support.AbstractApplicationContext prepareRefresh
정보: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@40c19080: startup date [Thu Dec 26 16:34:58 KST 2013]; root of context hierarchy
12월 26, 2013 4:34:58 오후 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
정보: Loading XML bean definitions from class path resource [ApplicationContext.xml]
12월 26, 2013 4:34:58 오후 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
정보: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5b43c919: defining beans [cal,logPrintbeforeAdvice,proxy]; root of factory hierarchy
Before Method Start
12월 26, 2013 4:34:58 오후 AOP3.LogPrintBeforeAdvice before
정보: [Method Before ]: 이전 보조 업무 시작 
800
Before Method Start
150000
12월 26, 2013 4:34:58 오후 AOP3.LogPrintBeforeAdvice before
정보: [Method Before ]: 이전 보조 업무 시작 
------------------------------------------------결과값 

5. 이번엔 After 기능에 대해서 알아보겠음
   4번과 마찬가지로 패키지 생성 (편의상 AOP4로 칭함)
   그리고 설정 파일 xml 과 설정 java 파일 을 제외한 
      나머지 내용을 복사해두고
   3개 클래스 이외의 LogPrintAroundAdvice.java 도 가져오도록 함
      (해당 내용이 실행되는 시점이 언제인지 확인하기 위해서)
   이전 것과 다른점만 확인하기로 함

먼저 AfterReturning.java 파일을 생성하고 다음과 같이 작성함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package AOP4;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;
public class AfterReturning implements AfterReturningAdvice{
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args,
            Object target) throws Throwable {
      System.out.println("[afterReturning] start...");
      Log log = LogFactory.getLog(this.getClass());
      log.info("[After MethodName ] " + method.getName() + 
                  " / Return Value : "+ returnValue +
                  " / args" + Arrays.toString(args));
   }
}

그리고 xml 파일을 다음과 같이 수정함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
   <bean id="cal" class="AOP4.NewCalc"></bean>
   <bean id ="logPrintAroundAdvice" class="AOP4.LogPrintAroundAdvice"></bean>
   <bean id ="afterReturning" class="AOP4.AfterReturning"></bean>
   <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <list>
            <value>AOP4.Calc</value>
         </list>
      </property>
      <property name="target" ref="cal"></property>
      <property name="interceptorNames">
         <list>
            <value>afterReturning</value>
            <value>logPrintAroundAdvice</value>
         </list>
      </property>
   </bean>
</beans>

여기선 after 적용시점인지 언제 인지 확인하기 위해 AOP2에서 실습했던 
LogPrintAroundAdvice.java 를 가져옴

------------------------------------------------결과값 
12월 26, 2013 4:56:06 오후 org.springframework.context.support.AbstractApplicationContext prepareRefresh
정보: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@76bc3ed6: startup date [Thu Dec 26 16:56:06 KST 2013]; root of context hierarchy
12월 26, 2013 4:56:06 오후 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
정보: Loading XML bean definitions from class path resource [ApplicationContext.xml]
12월 26, 2013 4:56:06 오후 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
정보: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@26ffab3f: defining beans [cal,logPrintAroundAdvice,afterReturning,proxy]; root of factory hierarchy
Invoke Method Start
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: 타이머 시작
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: 타이머 정지
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: [TimeLOG] Method : public abstract int AOP4.Calc.ADD(int,int)
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: [TimeLOG] process Time : 1
[afterReturning] start...
12월 26, 2013 4:56:06 오후 AOP4.AfterReturning afterReturning
정보: [After MethodName ] ADD / Return Value : 800 / args[500, 300]
800
Invoke Method Start
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: 타이머 시작
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: 타이머 정지
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: [TimeLOG] Method : public abstract int AOP4.Calc.MUL(int,int)
12월 26, 2013 4:56:06 오후 AOP4.LogPrintAroundAdvice invoke
정보: [TimeLOG] process Time : 0
[afterReturning] start...
12월 26, 2013 4:56:06 오후 AOP4.AfterReturning afterReturning
정보: [After MethodName ] MUL / Return Value : 150000 / args[500, 300]
150000
------------------------------------------------결과값 

6. Advice 의 throw 발생시 실행되는 advice 를 구현하도록 함
   새로운 패키지를 만드는데 편의상 AOP5 라고 명칭하고 해당 밑에
      이전에 사용했던 클래스들을 복사해 둠
   그리고 LogPrintAfterThrowingAdvice.java 및 xml 을 아래와 같이 수정함

1
2
3
4
5
6
7
8
9
10
package AOP5;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.ThrowsAdvice;
public class LogPrintAfterThrowingAdvice implements ThrowsAdvice{
   public void afterThrowing(IllegalArgumentException e) throws Throwable{
      Log log = LogFactory.getLog(this.getClass());
      log.info("[After Throwing 예외발생] : " + e.getMessage());  
   }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
   <bean id="cal" class="AOP5.NewCalc"></bean>
   <bean id ="logPrintAfterThrowingAdvice" class="AOP5.LogPrintAfterThrowingAdvice"></bean>
   <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <list>
            <value>AOP5.Calc</value>
         </list>
      </property>
      <property name="target" ref="cal"></property>
      <property name="interceptorNames">
         <list>
            <value>logPrintAfterThrowingAdvice</value>
         </list>
      </property>
   </bean> 
</beans>

------------------------------------------------결과값 
정보: [After Throwing 예외발생] : Y값이 X값보다 큽니다.
Exception in thread "main" java.lang.IllegalArgumentException: Y값이 X값보다 큽니다.
at AOP5.NewCalc.SUB(NewCalc.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy0.SUB(Unknown Source)
at AOP5.CalcMain.main(CalcMain.java:33)
------------------------------------------------결과값 


7. 설정된 advice 중에서 PointCut 을 구현 

   PointCut는 advice는 설정된 클래스에 포함된 전체 함수를 
      다 실행하는걸 기본으로 알고 있는데
   PointCut 을 설정해두면 설정한 클래스에서 실행할 함수를
      골라서 쓸수 있는 장점이 있음
   우선 패키지를 하나 만들고(편의상 AOP6으로 칭한다.)
   main, 인터페이스, 인터페이스 상속받은거 , LogPrintAroundAdvice.java 
      네개는 복사해둔다.
   여기서는 순수하게 ApplicationContext.xml  설정만 정리하면 가능하다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="UTF-8"?>
   <bean id="cal" class="AOP6.NewCalc"></bean>
   <bean id ="logPrintAroundAdvice" class="AOP6.LogPrintAroundAdvice"></bean>
   <bean id ="logPrintbeforeAdvice" class="AOP6.LogPrintBeforeAdvice"></bean>
   <bean id ="afterReturning" class="AOP6.AfterReturning"></bean>
   <bean id ="logPrintAfterThrowingAdvice" class="AOP6.LogPrintAfterThrowingAdvice"></bean>
<!-- ************PointCut으로 설정하기******************************** -->
   <bean id="nameMatchMethodPointcut" 
            class="org.springframework.aop.support.NameMatchMethodPointcut">
<!--  여러 함수를 같이 pointcut 할때 쓰는 경우 -->
      <property name="mappedNames" >
         <list>
            <value>ADD</value>
            <value>MUL</value>
         </list>
      </property>
   </bean>
<!-- ************Advisor 함수 이름으로 설정하기************************************* -->
   <bean id="defaultPointcutAdvisor" 
            class="org.springframework.aop.support.DefaultPointcutAdvisor"> 
<!-- 사용할 PointCut 은 무엇이고  -->
      <property name="pointcut" ref= "nameMatchMethodPointcut"></property> 
<!-- 어떤 advice를 포인트에 연결할 것인지를 결정 -->
      <property name="advice" ref="logPrintAroundAdvice"></property> 
 </bean> 
   <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <list>
            <value>AOP6.Calc</value>
         </list>
      </property>
      <property name="target" ref="cal"></property>
      <property name="interceptorNames">
         <list>
            <value>logPrintbeforeAdvice</value>
            <value>afterReturning</value>
            <value>logPrintAfterThrowingAdvice</value> -->
            <value>defaultPointcutAdvisor</value>
         </list>
      </property>
   </bean> 
</beans>

------------------------------------------------결과값 
12월 26, 2013 5:31:06 오후 org.springframework.context.support.AbstractApplicationContext prepareRefresh
정보: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@40c19080: startup date [Thu Dec 26 17:31:06 KST 2013]; root of context hierarchy
12월 26, 2013 5:31:06 오후 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
정보: Loading XML bean definitions from class path resource [ApplicationContext.xml]
12월 26, 2013 5:31:07 오후 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
정보: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5b43c919: defining beans [cal,logPrintAroundAdvice,logPrintbeforeAdvice,afterReturning,logPrintAfterThrowingAdvice,nameMatchMethodPointcut,defaultPointcutAdvisor,proxy]; root of factory hierarchy
-20
Invoke Method Start
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: 타이머 시작
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: 타이머 정지
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: [TimeLOG] Method : public abstract int AOP6.Calc.ADD(int,int)
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: [TimeLOG] process Time : 1
800
Invoke Method Start
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: 타이머 시작
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: 타이머 정지
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: [TimeLOG] Method : public abstract int AOP6.Calc.MUL(int,int)
12월 26, 2013 5:31:07 오후 AOP6.LogPrintAroundAdvice invoke
정보: [TimeLOG] process Time : 1
150000
------------------------------------------------결과값 

8. 추가적으로 7번 xml 설정 파일에서 

1
2
3
4
5
6
7
8
9
10
11
<!-- ************PointCut으로 설정하기******************************** -->
   <bean id="nameMatchMethodPointcut" 
            class="org.springframework.aop.support.NameMatchMethodPointcut">
<!--  여러 함수를 같이 pointcut 할때 쓰는 경우 -->
       <property name="mappedNames" >
         <list>
            <value>ADD</value>
            <value>MUL</value>
         </list>
      </property>
   </bean>
이 부분을 다음과 같이 치환 가능하다. 

(1) 하나의 함수를 실행하면 되는 경우

1
2
3
   <bean id="nameMatchMethodPointcut" 
            class="org.springframework.aop.support.NameMatchMethodPointcut">
      <property name="mappedNames" value="ADD"></property> 

(2) 조건식(정규식) 을 이용하고자 하는 경우

1
2
3
4
5
6
7
8
9
10
   <bean id="regexpMethodPointcutAdvisor" 
            class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> 
      <property name="patterns" >
         <list>
            <value>.*AD.*</value>
            <value>.*L</value>
         </list>
      </property>
      <property name="advice" ref="logPrintAroundAdvice"></property>
   </bean>

댓글 없음:

댓글 쓰기