Spring AOP面向切面編程

      最近在系統中須要實現用戶某些操做添加積分, 但願實現對系統現有的代碼進行最小嵌入,所以使用Spring AOP的切面編程將很好實現該需求,達到最小耦合度。在Spring AOP中的通知都是針對方法層級進行通知,相對與Struct中針對類層級通知,具備更好的靈活性。
html

 

        /*方法攔截*/
        MethodInterceptor
        
        /*返回攔截*/
        AfterReturningAdvice
        
        /*事件攔截*/
        HandlerInterceptor

        MethodInvocation

 

  • Spring對AOP的支持具備如下4種狀況:

 

             一、經典的基於代理的AOP(各版本Spring)
java

             二、@AspectJ註解驅動的切面(僅Spring 2.0);
正則表達式

             三、純POJO切面(僅Spring2.0);
spring

             四、注入式AspectJ切面(各版本Spring)express

             前三種都是基於代理的AOP的變體,所以,Spring對AOP的支持侷限於方法注入。若是咱們的AOP需求超過了簡單方法注入的範疇(好比構造器或屬性注入),就應該考慮在AspectJ裏實現切面,利用Spring的從屬注入把Spring的Bean注入到AspectJ切面

 

  • 在spring aop中有如下四種通知類型,本次使用的是after returning advice方式的通知。

              一、before advice 在方法執行前執行。
              二、after returning advice 在方法執行後返回一個結果後執行
              三、after throwing advice 在方法執行過程當中拋出異常後執行
              四、around advuce 綜合執行以上三種狀況編程

  

  • 典型Spring AOP編程的三個步驟

             一、建立通知:實現通知的這幾個接口,並實現其中的方法app

                    a)org.springframework.aop.MethodBeforeAdvice框架

                    b)org.springframework.aop.AfterReturningAdviceide

                    c)org.springframework.aop.ThrowsAdviceui

                    d)org.aopalliance.intercept.MethodInterceptor

                    e)org.springframework.aop.IntroductionInterceptor

             二、定義切點和通知者:在Spring配製文件中配置這些信息
             三、使用ProxyFactoryBean來生成代理

  • 建立通知advice

 

 

  •  定義切入點pointcut和通知

              要想實現Spring AOP  僅僅針對某一指定的方法進行切面編程,而不是針對全部的方法進行切面編程,那麼須要指定切入點(pointcut) ,pointcut經過制定方法名進行攔截方法,同時pointcut必須advisor進行關聯。pointcut能夠經過指定徹底方法名或經過正則表達式進行匹配方法。

  • 定義一個經過徹底方法名匹配方法的切入點

 

      <bean id="namePointCut" class="org.springframework.aop.support.NameMatchMethodPointcut">  
          <property name="mappedName" value="insertTestStudent" />  
      </bean>  

            org.springframework.aop.support.NameMatchMethodPointcut:表示該切點經過直接經過徹底方法名匹配方法的,property中的value就是完整的方法名。

  • 經過正則表達式匹配方法

 

      <bean id="addGuideIntegralAfterTesting" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
          <property name="pattern" value=".*insertTestStudent"/>
      </bean>

 

           結合通知者advisor

 

     <bean id="audienceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
        <property name="advice" ref="audienceAdvice" />  
        <property name="pointcut" ref="performancePointcut" />  
     </bean>  

          org.springframework.aop.support.DefaultPointcutAdvisor是個通知者類,他只是把通知關聯給切入點

 

  • 聯合切入點

              聯合切入點是比較特殊的正則表達式切入點,他同時結合了切入點和通知者

 

 

      <bean id="addGuideIntegralAfterTesting" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  	   <property name="advice" ref="guideIntegralAfterAdvice" />
  	   <property name="patterns">
   	       <list>
    	           <value>.*insertTestStudent</value>
   	       </list>
  	   </property>
 	</bean> 
  • AspectJ 切點

              從AspectJ裏定義切點的方式就能夠看出AspectJ的切點語言是一種真正的切點表達語言。 類org.springframework.aop.aspectj.AspectJExpressionPointcut被用來定義AspectJ切點表達式

 

       <bean id="performancePointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">  
           <property name="expression" value="execution(* Performer+.perform(..))" />  
       </bean> 

 

            經過使用DefaultPointcutAdvisor把切入點和通知者結合起來。咱們能夠利用特殊的通知者,把切點表達式定義爲通知者的一個屬性。對於AspectJ表達式來講,使用的通知者類是org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor:

 

    <bean id="audienceAdvisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">  
        <property name="advice" ref="audienceAdvice" />  
        <property name="expression" value="execution(* Performer+.perform(..))" />  
    </bean>  


             通知者把通知與切點關聯起來,從而完整地定義一個切面。

 


  • Spring 代理

            切面在Spring裏是以代理方式實現的,因此仍然須要代理目標Bean才能讓通知者發揮做用,如下有兩種方式顯示代理,一經過ProxyFactoryBean方式或者經過自動代理。

 

       
      <!--定義個聯合代理-->
      <bean id="addIntegralAutoProxyAop" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames">
               <list>
                <!--須要監聽的接口-->
                <value>guideStudentService</value>
               </list>
          </property>
  
          <property name="interceptorNames">
               <list>
                <!-- 與第一個bean的id相匹配 -->
                <value>addGuideIntegralAfterTesting</value>
               </list>
          </property>
     </bean>    
  • ProxyFactoryBean代理

             Spring的ProxyFactoryBean是個工廠Bean,用於生成一個代理,把一個或多個通知者應用到Bean

    <bean id="duke" class="org.springframework.aop.framework.ProxyFactoryBean">  
        <property name="target" ref="dukeTarget" />  
        <property name="interceptorNames">  
            <list>  
                <value>audienceAdvisor</value>  
            </list>  
        </property>  
    </bean>  
  • 自動代理

 

              自動代理可以讓切面的切點定義來決定哪一個Bean須要代理,不須要咱們爲特定的Bean明確地建立代理,從而提供了一個更完整的AOP實現。實現自動代理Bean的方式有兩種:
              一、基於Spring上下文裏聲明的通知者Bean的基本自動代理」:通知者的切點表達式用於決定哪一個Bean和哪一個方法要被代理。
              二、基於@AspectJ註解驅動切面的自動代理」:切面裏包含的通知裏指定的切點將用於選擇哪一個Bean和哪一個方法要被代理。

             

 

 

      <!--定義個聯合代理-->
      <bean id="addIntegralAutoProxyAop" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames">
               <list>
                <!--須要監聽的接口-->
                <value>guideStudentService</value>
               </list>
          </property>
  
          <property name="interceptorNames">
               <list>
                <!-- 與第一個bean的id相匹配 -->
                <value>addGuideIntegralAfterTesting</value>
               </list>
          </property>
     </bean>    

 

  • 完整的配置信息

 

    <!-- 定義通知advice -->
    <bean id="guideIntegralAfterAdvice" class="com.rrtong.interceptors.GuideIntegralAfterAdvice" />
    <!-- 定義pointcut和通知者advisor的聯合切入點和通知者 -->
    <bean id="addGuideIntegralAfterTesting" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!-- 引用通知接口的實現類 -->
           <property name="advice" ref="guideIntegralAfterAdvice" />
        <!-- 正則表達式匹切入點方法名 -->
          <property name="patterns">
               <list>
                <value>.*insertTestStudent</value>
               </list>
          </property>
     </bean>
     
     <!-- 定義自動代理 -->
      <bean id="addIntegralAutoProxyAop" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
          <property name="beanNames">
               <list>
                <value>guideStudentService</value>
               </list>
          </property>
  
          <property name="interceptorNames">
               <list>
                <value>addGuideIntegralAfterTesting</value>
               </list>
          </property>
     </bean>    

 

  • 通知Advice

 

           切面的功能被稱爲Advice(通知),定義切面的工做內容,以及切面工做的時機,實在被攔截方法以前,以後,異常拋出時,仍是以上狀況都執行。

  • 鏈接點Joinpoint

             joinpoint就是程序執行過程當中可以插入到切面的一個點,這個點就是方法被調用時,異常拋出時,甚至字段被編輯時。切面代碼經過這個點插入到程序的通常流程中,從而添加新的行爲。

  • 切入點Pointcut

              pointcut做用就是縮小切面通知範圍

             切入點能夠縮小切面通知的鏈接點的範圍。若是說advice定義了切面的「什麼」和「什麼時候」,那麼切入點就定義了「何地」。切入點的定義匹配advice要織入的一個或多個鏈接點。咱們一般使用明確的類和方法名稱,或是利用正則表達式定義匹配的類和方法名稱模板來指定這些切入點。有些AOP框架容許建立動態切入點,能夠根據運行時的狀態(好比方法的參數值)來應用通知。

  •  切面Aspect
              切面就是通知和切入點的結合。通知和切入點共同定義了關於切面的所有內容——它的功能、在什麼時候和何地完成其功能。

  • 目標Target
              「目標」是被通知的對象,它能夠是咱們編寫的一個對象,或第三方對象。若是沒有AOP,這個對象就必須包含本身的主要邏輯和交叉事務的邏輯。經過使用AOP,目標對象就能夠着重於本身的主要邏輯,沒必要考慮要被應用的任何通知。

  • 代理Proxy
              代理是向目標對象應用通知以後被建立的對象。對於客戶對象來講,目標對象(AOP以前)和代理對象(AOP以後)是同樣的——它們就應用是這樣的。這樣一來,程序的其餘部分就沒必要修改對代理對象的支持。

  • 織入Weaving
             織入是把切面應用到目標對象來建立新的代理對象的過程。切面在指定鏈接點織入到目標對象。在目標對象的生命週期裏有多個時機能夠發生織入過程:

 

 

  • 參考資料

              http://blog.csdn.net/sin90lzc/article/details/7486145

              http://blog.163.com/zzf_fly/blog/static/209589158201382314454298/

              http://blog.csdn.net/topwqp/article/details/8695180

相關文章
相關標籤/搜索