2015년 4월 13일 월요일

SpringFramework 에서 *.xml 설정 파일 작성방법

1. web.xml 설정(기본만)
    다이나믹 웹 프로젝트에 기본 옵션으로 web.xml 을 설정할 수 있는데
    여기에 다음 내용을 추가해 주면 xxxxx-servlet.xml 이라는 명칭으로 
    Springframework 설정을 할수 있다.

1
2
3
4
5
6
7
8
<servlet>
    <servlet-name>xxxxx</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
    <servlet-mapping>
        <servlet-name>xxxxx</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>

여기서 servlet-name 명칭 -servlet.xml 이라는 이름으로 작성해야 한다.
 (내부 구조는 모르겠지만 약속되어 있음  여기서는 xxxxx-servlet.xml)

2. xxxxx-servlet.xml 파일 의 객체 등록하는 방법
(1) 빈 객체 올리기 첫번째

1
2
3
<bean name="쓸 아이디명칭 beanida"  
           id="클래스 위치 및 클래스 명칭kr.com.SpringFrameworkabout">
</bean>

(2)빈 객체 올리기 두번째- static 객체 올리기
       만약에 끌어올 객체가(클래스가) getInstance로 호출되야만 객체를 생성할 수 있는
         static 선언된 객체일 경우 컨테이너에 올리는 설정 방법이다.
       뒤에 저거만 붙여주면 됨

1
2
3
4
<bean name="쓸 아이디명칭 beanida"  
           id="클래스 위치 및 클래스 명칭kr.com.SpringFrameworkabout"
           factory-method="getInstance">
</bean>

(3) 빈객체 올리기 세번째- 생성자에 의존 클래스 추가해서 작성하기
      생성자에 다른 클래스가 포함되어 있는경우 태그 하나를 추가함

1
2
3
4
5
6
<bean name="쓸 아이디명칭 beanida"  
           id="클래스 위치 및 클래스 명칭kr.com.SpringFrameworkabout">
<constructor-arg>
<ref bean="클래스 위치 및 명칭"/>
</constructor-arg>
</bean>

(4) 빈객체 올리기 네번째 setxxx() 함수를 사용해서 
     static 이 아닌 객체 올리기
     방법 : constructor-arg 대신에 아래 내용을 대체함

1
2
3
<property name="프로퍼티 이름(임의로 부여하는거">
   <reg bean="클래스 명칭">
 </property>

(5) peoperty 에 기본 데이터 타입의 변수를 붙이기

1
2
3
4
5
6
7
<property name="프로퍼티 이름(임의로 부여하나 변수명과 일치함">
   <value>3</value>
 </property>
<property name="프로퍼티 이름(임의로 부여하는거" ref="추가해야할 클래스 이름">
   <reg bean="클래스 명칭"/>
 </property>

 (6) (4)번 내용은 아래 내용으로 치환 가능함

1
2
    p:프로퍼티 이름 ="3"
    p:프로퍼티 이름-ref="클래스 명칭"

(7) 특정 메소드를 사용해야만(다른클래스의) 객체가 생성되는 경우
      방법 :  lookup-method 를 이용함

1
2
3
<bean........>
<lookup-method name="쓸 메소드명칭" bean="메소드가 포함된 클래스명칭"/>
</bean>
ps . CGLIB 라는 cglib-nodep-2.1.jar 파일을 라이브러리에 추가해야함

(8) 배열 형태(List, map, set, 등등)을 
    방법: 입력 형태니깐 자료를 직접 입력하는 형태이다.
            안에 다음과 같은 코드를 삽입하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<bean.............>
     <peoperty name="">
             <map>
                      <entry>
                            <key><value></value><key>
                            <ref bean="">
                      </entry>
                      <entry>
                            <key><value>2값</value><key>
                            <ref bean="">
                      </entry>
             </map>
     </peoperty>
</bean>

 (8)-2 List 의 경우 
    <map>  부분은 아래와 같이 바뀌게 됨

1
2
3
4
<list>
        <value>1</value>
        <value>2</value>
</list>

(8)-3 set type(배열인데 중복을 체크해주는 형태)

1
2
3
4
5
6
<property name="subset">
   <set value-type="java.lang.Integer">
      <value>10</value>
      <value>20</value>
   </set
</property>

(9) Properties 타입(Map 인데 환경설정을 위한 타입)

1
2
3
4
5
6
7
8
<bean name="client" class="com.spring.bookclient">
   <property name="config">
      <props>
         <prop key="server">localhost</prop>
         <prop key="id">samgugji</prop>
      </props>
   </property>
</bean>


3. xxxxx-servlet.xml 파일 의 의존 관계 설정
(1) 기본적인 스타일

1
2
3
4
<bean name="/customer/noticeDetail.htm" class="controllers.customer.NoticeDetailController">
   <property name="noticeDao" ref="noticeDao"></property>
      </bean>
<bean id="noticeDao" class="dao.NoticeDao"></bean>

이렇게 하면 NoticeDao.java 객체를 NoticeDetailController 
라는 클래스에서 참조할수 있게 설정되었다.

(2) byName , byType 를 property 설정 대신에 autowire="byName" 
            이렇게 넣어준다면 좀더 쉽게 객체를 연결 할수 있다.

1
2
3
4
<bean name="/customer/noticeDetail.htm" 
class="controllers.customer.NoticeDetailController" autowire="byName">
</bean>
<bean id="noticeDao" class="dao.NoticeDao"></bean>

      byName : 이름이 같은 빈 객체를 설정한다. 
                    (물론 빈에 등록된 이름 == .java에서 호출한 이름과 동일)
      byType : 타입이 같다고 생각되는 객체를 입력해준다.
                   (같은 인터페이스를 상속한 객체들(2개이상)이 빈에 등록되어
                      있다면 에러를 유발하게 된다.)
      -- 둘중 하나라도 이름이 바뀌면 엉킬수 있으므로 주의 해야 함.
      constructor : byType 이나 빈에 등록된 객체중에서 선택하되
                    java 파일에 생성된 생성자에서 언급한 파일을 읽어옴
      autodetect : byType 과 동일함
   + 위의 4가지 자동설정 에 수동설정 방법도 같이 쓸수 있음

(3) 부모님 설정 가능

1
2
3
4
5
6
7
8
9
<bean name="noticeDetail.htm" class="controllers.customer.NoticeDetailController">
   <property name="Time" value="100"></property>
</bean>
<bean name="반치스Detail.htm" class="controllers.customer.NoticeDetailController">
   <property name="Time" value="100"></property>
</bean>
<bean name="치토스noticeDetail.htm" class="controllers.customer.NoticeDetailController">
   <property name="Time" value="100"></property>
</bean>

   위와 같이 이름만 틀리고 클래스, 참조하는 변수값이 동일한 경우 
     parent 설정을 가질수 있음

1
2
3
4
5
6
7
<bean name="common.htm" class="controllers.customer.NoticeDetailController">
   <property name="Time" value="100"></property>
</bean>
<bean id="door" parent="common">
<bean id="window" parent="common">
<bean id="human" parent="common">

4. xxxxx-servlet.xml 파일의 범위 설정
(1) 보통 싱글톤으로 생성해 쓰는데 호출시마다 생성하고자 할때가 있음
       이때 scope="" 옵션으로 조절이됨

1
2
3
<bean name="common.htm" class="controllers.customer.NoticeDetailController" scope="">
   <property name="Time" value="100"></property>
</bean>

       singleton : 스프링 컨테이너1개 1객체 존재 
       prototype : 빈 사용시마다 생성
       request : HTTP 요청시마다 생성
       session : HTTP 세션 open 시 1객체 생성
       golbal-session : 글로벌 HTTP 세션에 1객체 생성
                                   포플릿(?) 적용 객체에만 적용됨

(2) 충돌상황 : 싱글톤 객체A가 prototype 객체B를 쓰려고 할때 
       A객체가 더이상 만들어지지않아 B 객체도 A갯수만큼만 생성된다.
       이걸 굳이 쓰고자 한다면
       (A에서 B 호출시마다 B객체 새로 생성) 아래와 같이
           beans에 3줄을 포함하고)

1
2
3
4
5
6
7
8
9
10
11
12
13
14

bean 설정에 다음 <aop:scoped-proxy/> 라는 옵션을 추가해준다.

1
2
3
4
5
6
7
<bean name="common" class="controllers.customer.NoticeDAO" scope="">
   <aop:scoped-proxy/>
</bean>

<bean name="simple.htm" class="controllers.customer.Controller" scope="">
   <property name="common" ref="common" />
</bean>



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>