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

相关文章
相关标签/搜索