Chan Chen Coding...

          Spring AOP

          Spring AOP 簡單理解

          AOP技術即(面向切面編程)技術是在面向對象編程基礎上的發展,AOP技術是對所有對象或一類對象編程。核心是在不增加代碼的基礎上,還增加了新的功能。AOP編程在開發框架本身用的比較多,而實際項目中,用的比較少。它是將分散在各個業務邏輯代碼中的相同代碼抽取出來形成一個獨立的模塊。

          1、定義AOP術語

          (1)切面(aspect):要實現的交叉功能,是系統模塊化的一個切面或領域。

          (2)通知(advice):切面的具體實現,包含五類通知。

          (3)連接點(jointpoint):應用程序執行過程中插入切面的地點。

          (4)切點(cutpoint):定義通知應該應用哪些連接點。

          (5)引入(introduction):為類添加新方法和屬性。

          (6)目標對象(target):通知邏輯的織入目標類。

          (7)代理(proxy):將通知應用到目標對象后創建的對象,應用系統的其他部分不用為了支持代理對象而改變

          (8)織入(weaving):將切面應用到目標對象從而創建一個新代理對象的過程。

           

          2、AOP原理和實例

          (1)基礎接口和類的實現:

          package com.jasson.aop;

          public interface TestServiceInter1 {

              public void sayHello();
          }


          package com.jasson.aop;

          public interface TestServiceInter2 {

              public void sayBye();
              
              public void sayHi();
          }

          (2)實現類如下:
          package com.jasson.aop;

          public class TestService implements TestServiceInter1,TestServiceInter2 {

              public void sayHello() {
                  System.out.println("sayHello() method ");
              }

              public void sayBye() {
                  System.out.println("sayBye() method");
              }
              
              public void sayHi() {
                  System.out.println("sayHi() method");
              }
          }

          (1)前置通知:要求在每個方法調用前進行日志記錄,則用的前置通知,定義如下:

          package com.jasson.aop;

          import java.lang.reflect.Method;

          import org.springframework.aop.MethodBeforeAdvice;

          public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

              /**
               * method: 方法名
               * args: 輸入參數
               * target: 目標對象
               
          */
              public void before(Method method, Object[] args, Object target)
                      throws Throwable {
                  System.out.println("前置通知調用 記錄日志"+method.getName());
              }
          }

          配置文件如下:

           

          <?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:context="http://www.springframework.org/schema/context"
                  xmlns:tx="http://www.springframework.org/schema/tx"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                          >
          <!-- 配置被代理的對象,即目標對象 -->
          <bean id="testService" class="com.jasson.aop.TestService" />
          <!-- 配置前置通知 -->
          <bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
          <!-- 配置代理對象 -->
          <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
              <!-- 代理接口集 -->
              <property name="proxyInterfaces">
                  <list>
                      <value>com.jasson.aop.TestServiceInter1</value>
                      <value>com.jasson.aop.TestServiceInter2</value>
                  </list>
              </property>
              <!-- 把通知織入到代理對象  -->
              <property name="interceptorNames">
                  <!-- 相當于包MyMethodBeforeAdvice前置通知和代理對象關聯,我們也
                  可以把通知看出攔截器,struts2核心攔截器 -->
                  <list>
                      <value>myMethodBeforeAdvice</value>
                  </list>
              </property>
              <!-- 配置被代理對象,即目標對象 -->
              <property name="target" ref="testService"/>
          </bean>
          </beans>
           

          package com.jasson.aop;

          import org.springframework.context.ApplicationContext;
          import org.springframework.context.support.ClassPathXmlApplicationContext;

          public class App1 {

              /**
               * 
          @param args
               
          */
              public static void main(String[] args) {
                  // TODO Auto-generated method stub
                  ApplicationContext ac=new ClassPathXmlApplicationContext("com/jasson/aop/beans.xml");
                  TestServiceInter1 ts=(TestServiceInter1) ac.getBean("proxyFactoryBean");
                  ts.sayHello();
                  System.out.println("*******************************************");
                  ((TestServiceInter2)ts).sayBye();
                  System.out.println("*******************************************");
                  ((TestServiceInter2)ts).sayHi();
              }
          } 

           執行結果如下:

          31-May-2012 18:19:53 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
          INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@c8f6f8: defining beans [testService,myMethodBeforeAdvice,
          myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,proxyFactoryBean]; root of factory hierarchy
          前置通知調用 記錄日志sayHello
          sayHello() method 
          *******************************************
          前置通知調用 記錄日志sayBye
          sayBye() method
          *******************************************
          前置通知調用 記錄日志sayHi
          sayHi() method

          (2)后置通知:要求在調用每個方法后執行的功能,例如在調用每個方法后關閉資源

           

          package com.jasson.aop;

          import java.lang.reflect.Method;

          import org.springframework.aop.AfterReturningAdvice;

          public class MyAfterReturningAdvice implements AfterReturningAdvice {

              @Override
              public void afterReturning(Object returnValue, Method method, Object[] arg,
                      Object target) throws Throwable {
                  // TODO Auto-generated method stub
                  System.out.println("后置通知調用,關閉資源"+method.getName());
              }
          }
           bean 配置如下:
          <?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:context="http://www.springframework.org/schema/context"
                  xmlns:tx="http://www.springframework.org/schema/tx"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                          >
          <!-- 配置被代理的對象,即目標對象 -->
          <bean id="testService" class="com.jasson.aop.TestService" />
          <!-- 配置前置通知 -->
          <bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
          <!-- 配置后置通知 -->
          <bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
          <!-- 配置代理對象 -->
          <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
              <!-- 代理接口集 -->
              <property name="proxyInterfaces">
                  <list>
                      <value>com.jasson.aop.TestServiceInter1</value>
                      <value>com.jasson.aop.TestServiceInter2</value>
                  </list>
              </property>
              <!-- 把通知織入到代理對象  -->
              <property name="interceptorNames">
                  <!-- 相當于包MyMethodBeforeAdvice前置通知和代理對象關聯,我們也
                  可以把通知看出攔截器,struts2核心攔截器 -->
                  <list>
                      <value>myMethodBeforeAdvice</value>
                      <value>myAfterReturningAdvice</value>
                  </list>
              </property>
              <!-- 配置被代理對象,即目標對象 -->
              <property name="target" ref="testService"/>
          </bean>
          </beans>

          執行結果如下:

           

          INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@122cdb6: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,proxyFactoryBean]; root of factory hierarchy
          前置通知調用 記錄日志sayHello
          sayHello() method 
          后置通知調用,關閉資源sayHello
          *******************************************
          前置通知調用 記錄日志sayBye
          sayBye() method
          后置通知調用,關閉資源sayBye
          *******************************************
          前置通知調用 記錄日志sayHi
          sayHi() method

          后置通知調用,關閉資源sayHi 

          (3)環繞通知:指在某個具體的方法中,添加相應的操作

          package com.jasson.aop;

          import org.aopalliance.intercept.MethodInterceptor;
          import org.aopalliance.intercept.MethodInvocation;

          public class MyMethodInterceptor implements MethodInterceptor {

              @Override
              public Object invoke(MethodInvocation arg) throws Throwable {
                  // TODO Auto-generated method stub
                  System.out.println("環繞通知調用方法前");
                  Object obj = arg.proceed();
                  System.out.println("環繞通知調用方法后");
                  return obj;
              }
          }

          配置文件如下:

          <?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:context="http://www.springframework.org/schema/context"
                  xmlns:tx="http://www.springframework.org/schema/tx"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                          >
          <!-- 配置被代理的對象,即目標對象 -->
          <bean id="testService" class="com.jasson.aop.TestService" />
          <!-- 配置前置通知 -->
          <bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
          <!-- 配置后置通知 -->
          <bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
          <!-- 配置環繞通知 -->
          <bean id="myMethodInterceptor" class="com.jasson.aop.MyMethodInterceptor" />
          <!-- 配置代理對象 -->
          <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
              <!-- 代理接口集 -->
              <property name="proxyInterfaces">
                  <list>
                      <value>com.jasson.aop.TestServiceInter1</value>
                      <value>com.jasson.aop.TestServiceInter2</value>
                  </list>
              </property>
              <!-- 把通知織入到代理對象  -->
              <property name="interceptorNames">
                  <!-- 相當于包MyMethodBeforeAdvice前置通知和代理對象關聯,我們也
                  可以把通知看出攔截器,struts2核心攔截器 -->
                  <list>
                      <value>myMethodBeforeAdvice</value>
                      <value>myAfterReturningAdvice</value>
                      <value>myMethodInterceptor</value>
                  </list>
              </property>
              <!-- 配置被代理對象,即目標對象 -->
              <property name="target" ref="testService"/>
          </bean>
          </beans>
           執行結果如下:
          INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ce2dd4: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,proxyFactoryBean]; root of factory hierarchy
          前置通知調用 記錄日志sayHello
          環繞通知調用方法前
          sayHello() method 
          環繞通知調用方法后
          后置通知調用,關閉資源sayHello
          *******************************************
          前置通知調用 記錄日志sayBye
          環繞通知調用方法前
          sayBye() method
          環繞通知調用方法后
          后置通知調用,關閉資源sayBye
          *******************************************
          前置通知調用 記錄日志sayHi
          環繞通知調用方法前
          sayHi() method
          環繞通知調用方法后
          后置通知調用,關閉資源sayHi
           (4)異常通知:當發生異常時,要執行的通知
          package com.jasson.aop;

          import java.lang.reflect.Method;

          import org.springframework.aop.ThrowsAdvice;

          public class MyThrowsAdvice implements ThrowsAdvice {

              public void afterThrowing(Method method, Object[] os, Object target,
                      Exception exception) {

                  System.out.println("異常通知產生異常,進行處理" + exception.getMessage());
              }
          }
           

           

          <?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:context="http://www.springframework.org/schema/context"
                  xmlns:tx="http://www.springframework.org/schema/tx"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                          >
          <!-- 配置被代理的對象,即目標對象 -->
          <bean id="testService" class="com.jasson.aop.TestService" />
          <!-- 配置前置通知 -->
          <bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
          <!-- 配置后置通知 -->
          <bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
          <!-- 配置環繞通知 -->
          <bean id="myMethodInterceptor" class="com.jasson.aop.MyMethodInterceptor" />
          <!-- 配置異常通知 -->
          <bean id="myThrowsAdvice" class="com.jasson.aop.MyThrowsAdvice" />
          <!-- 配置代理對象 -->
          <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
              <!-- 代理接口集 -->
              <property name="proxyInterfaces">
                  <list>
                      <value>com.jasson.aop.TestServiceInter1</value>
                      <value>com.jasson.aop.TestServiceInter2</value>
                  </list>
              </property>
              <!-- 把通知織入到代理對象  -->
              <property name="interceptorNames">
                  <!-- 相當于包MyMethodBeforeAdvice前置通知和代理對象關聯,我們也
                  可以把通知看出攔截器,struts2核心攔截器 -->
                  <list>
                      <value>myMethodBeforeAdvice</value>
                      <value>myAfterReturningAdvice</value>
                      <value>myMethodInterceptor</value>
                      <value>myThrowsAdvice</value>
                  </list>
              </property>
              <!-- 配置被代理對象,即目標對象 -->
              <property name="target" ref="testService"/>
          </bean>
           

          package com.jasson.aop;

          public class TestService implements TestServiceInter1,TestServiceInter2 {

              public void sayHello() {
                  System.out.println("sayHello() method ");
              }

              public void sayBye() {
                  System.out.println("sayBye() method");
              }
              
              public void sayHi() {
                  int a =10/0;
                  System.out.println("sayHi() method");
              }
          }
           
          執行結果如下:
          INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ce2dd4: defining beans [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,proxyFactoryBean]; root of factory hierarchy
          前置通知調用 記錄日志sayHello
          環繞通知調用方法前
          sayHello() method 
          環繞通知調用方法后
          后置通知調用,關閉資源sayHello
          *******************************************
          前置通知調用 記錄日志sayBye
          環繞通知調用方法前
          sayBye() method
          環繞通知調用方法后
          后置通知調用,關閉資源sayBye
          *******************************************
          前置通知調用 記錄日志sayHi
          環繞通知調用方法前
          異常通知產生異常,進行處理/ by zero
          Exception in thread "main" java.lang.ArithmeticException: / by zero 

          (5)上面的通知都是針對每個方法的,如果只是對單個或者一類的方法進行相應處理的時,可采用名字或者正則表達式的方式進行處理

          配置如下:

          <?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:context="http://www.springframework.org/schema/context"
                  xmlns:tx="http://www.springframework.org/schema/tx"
                  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
                          >
          <!-- 配置被代理的對象,即目標對象 -->
          <bean id="testService" class="com.jasson.aop.TestService" />
          <!-- 配置前置通知 -->
          <bean id="myMethodBeforeAdvice" class="com.jasson.aop.MyMethodBeforeAdvice" />
          <!-- 配置后置通知 -->
          <bean id="myAfterReturningAdvice" class="com.jasson.aop.MyAfterReturningAdvice" />
          <!-- 配置環繞通知 -->
          <bean id="myMethodInterceptor" class="com.jasson.aop.MyMethodInterceptor" />
          <!-- 配置異常通知 -->
          <bean id="myThrowsAdvice" class="com.jasson.aop.MyThrowsAdvice" />

          <!-- 通知與正則表達式切入點一起配置 -->  
          <!-- Advisor等于切入點加通知,所有say開頭的方法添加前置通知 -->  
          <bean id="regexpPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
              <property name="advice" ref="myMethodBeforeAdvice"/>  
              <property name="patterns">  
                  <list>  
                      <value>.*say.*</value>  
                  </list>  
              </property>  
          </bean>  

          <!-- 方法名匹配切入點配置器:只對 sayHello方法添加環繞通知-->  
          <bean id="namePointcutAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">  
              <property name="advice" ref="myMethodInterceptor"/>  
              <property name="mappedNames">  
                  <list>  
                      <value>sayHello</value>  
                  </list>  
              </property>  
          </bean> 

          <!-- 配置代理對象 -->
          <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
              <!-- 代理接口集 -->
              <property name="proxyInterfaces">
                  <list>
                      <value>com.jasson.aop.TestServiceInter1</value>
                      <value>com.jasson.aop.TestServiceInter2</value>
                  </list>
              </property>
              <!-- 把通知織入到代理對象  -->
              <property name="interceptorNames">
                  <!-- 相當于包MyMethodBeforeAdvice前置通知和代理對象關聯,我們也
                  可以把通知看出攔截器,struts2核心攔截器 -->
                  <list>
                      <value>namePointcutAdvisor</value>
                      <value>myAfterReturningAdvice</value>
                      <value>regexpPointcutAdvisor</value>
                      <value>myThrowsAdvice</value>
                  </list>
              </property>
              <!-- 配置被代理對象,即目標對象 -->
              <property name="target" ref="testService"/>
          </bean>
          </beans>

          執行結果如下:

          INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1ef9157: defining beans 
          [testService,myMethodBeforeAdvice,myAfterReturningAdvice,myMethodInterceptor,myThrowsAdvice,regexpPointcutAdvisor,namePointcutAdvisor,proxyFactoryBean]; 
          root of factory hierarchy
          環繞通知調用方法前
          前置通知調用 記錄日志sayHello
          sayHello() method 
          后置通知調用,關閉資源sayHello
          環繞通知調用方法后
          *******************************************
          前置通知調用 記錄日志sayBye
          sayBye() method
          后置通知調用,關閉資源sayBye
          *******************************************
          前置通知調用 記錄日志sayHi
          異常通知產生異常,進行處理/ by zero
          Exception in thread "main" java.lang.ArithmeticException: / by zero


          -----------------------------------------------------
          Silence, the way to avoid many problems;
          Smile, the way to solve many problems;

          posted on 2012-12-27 11:30 Chan Chen 閱讀(219) 評論(0)  編輯  收藏 所屬分類: Scala / Java

          主站蜘蛛池模板: 文成县| 呈贡县| 扎囊县| 毕节市| 赤城县| 新邵县| 彰武县| 合水县| 含山县| 漠河县| 渭南市| 中阳县| 邵东县| 井研县| 怀来县| 凌海市| 新河县| 孙吴县| 齐齐哈尔市| 黄冈市| 茶陵县| 美姑县| 兴安县| 安溪县| 都安| 黑河市| 浑源县| 甘谷县| 浦江县| 梅河口市| 赤峰市| 广安市| 铁岭县| 英山县| 江川县| 平顺县| 平阳县| 枝江市| 雷州市| 张家界市| 南部县|