分享

spring aop支持

 碧海山城 2010-09-26
 
 
 

Spring只支持方法的JoinPoints,也就是Adivices将在方法执行的前后被引用,Spring不支持Field成员的Joinpoints,这是因为Spring的设计哲学中认为,支持Field成员的Joinpoints会破坏对象的封装性。

Advices

Advices实现了Aspectj的真正逻辑,根据蒋这些通知织入Targets的时机不同Spring提供了几种不同的通知,比如,BeforeAfterAroundThrow

1.Before

/**

 * 前置通知,在目标方法调用之前执行

 * @author Administrator

 *

 */

public class BeforeAdvicesTest implements MethodBeforeAdvice{

    public void before(Method method, Object[] args, Object target)

    throws Throwable {

        System.out.println("before execute");

     }

}

<bean id="before" class="com.bhsc.AOP.BeforeAdvicesTest"></bean>

<bean id="target" 

class="com.bhsc.AOP.target.TargetImple"></bean>

<bean id="helloProxy" 

class="org.springframework.aop.framework.ProxyFactoryBean">

        <property name="proxyInterfaces" 

value="com.bhsc.AOP.target.TargetInterface"/>

        <property name="target" ref="target"/>

        <property name="interceptorNames">

           <list>

             <value>before</value>

           </list>

        </property>

</bean>

通知实现了MethodBeforeAdvice,在配置中建立了AdviceTarget,还使用了ProxyFactoryBean,这个类会被BeanFactoryApplicationContext,用来建立代理对象,并配置了实现的接口,在不指定目标方法时,Before Advice会被织入到接口上的所有方法。

AdviceTarget并不是动态代理中的代理对象,而是真实的对象,也就是动态代理中传入的真正的类。

拿动态代理来对比下:

Object  proxy  =  Proxy.newProxyInstance(Monkey.class.getClassLoader(), 

Monkey.class.getInterfaces(), 

new MyInvocationHandler( new Monkey())); 

 可以看到动态代理中,真正的类是new时候传入的,而Spring则配置在文件中注入了。

2.After Before类似

3.Around

如果要在方法执行的前后,加入Advices的逻辑,可以直接通过实现org.aopalliance.intercept.MethodInterceptor接口,与Before和After不同的是,在MethodInterceptorinvoke方法中,我们可以自行决定是否使用它的proceed()方法来执行目标对象的方法,proceed会回传方法执行后的Object结果,所以在invoke结束之前,有机会修改对象,或是回传一个完全不相干的对象。
 

/**

 * Around通知,在真正执行某个方法前,会先插入Interceptor,如果有多个,则会一个个执行,然后执行method的方法,将执行流程转给下一个Interceptor,最后一层层返回堆栈,最后离开堆栈返回应用程序本身的流程。

 * @author Administrator

 *

 */

public class MethodInterceptorTest implements MethodInterceptor{

  public Object invoke(MethodInvocation methodInvocation) throws Throwable {

     System.out.println("execute method:"+methodInvocation.getMethod());

     Object result=null;

     result=methodInvocation.proceed();

     return result;

  }

}

<!-- around -->

<bean id="around" 

class="com.bhsc.AOP.MethodInterceptorTest"></bean>

<bean id="helloProxy" 

class="org.springframework.aop.framework.ProxyFactoryBean">

     <property name="proxyInterfaces" 

value="com.bhsc.AOP.target.TargetInterface"/>

     <property name="target" ref="target"/>

     <property name="interceptorNames">

        <list>

           <value>around</value>

        </list>

     </property>

</bean>

 

1.Throw 如果抛出的异常类型和发生的类型相同,那么就会执行通知方法。

前面的Advice,一定程度上也包括切入点,也就是一个类的所有方法,不过这些都是粗粒度的,事实上,我们可以定义更细粒度的,定义需要的方法,那就是PointCut


PointCutAdvisor

PointCut定义了Joinpoint的集合,表示Advice应用的时机(方法)。Spring中,用PointcutAdvisor表示PointCutAdvisor的结合,就是aspectPointcutAdvisorAdvisor的子接口:

public interface Advisor {


      Advice getAdvice();

   /**

    * @return whether this advice is associated with a particular target instance

    */

   boolean isPerInstance();

}
 

public interface PointcutAdvisor extends Advisor {

   /**

    * Get the Pointcut that drives this advisor.

    */

   Pointcut getPointcut();

}

分别有NameMatchMethodPointcutAdvisor、RegexpMethodPointcutAdvisor、ControlFlowPointcut


   1.
NameMatchMethodPointcutAdvisor ,最基本的PointcutAdvisor,可以使用表达式指定Advice应用目标上的方法名称。

<!-- NameMatchMethodPointcutAdvisor,以llo结尾的方法,使用前面定义的before通知,mappedName可以使用集合注入,那就是nammedNames -->

<bean id="helloAdvisor" class="org.springframework.aop.

support.NameMatchMethodPointcutAdvisor">

        <property name="mappedName" value="*llo"/>

        <property name="advice" ref="before"/>

</bean>
 

<bean id="helloAdvisorProxy"

 class="org.springframework.aop.framework.ProxyFactoryBean">

      <property name="proxyInterfaces" 

value="com.bhsc.AOP.target.TargetInterface"/>

      <property name="target" ref="target"/>

      <property name="interceptorNames">

         <list>

            <value>helloAdvisor</value>

         </list>

      </property>

</bean>
 

target中加入nihao方法:

public void nihao(String name){

System.out.println("你好 :"+name);

}

TargetInterface ti=(TargetInterface)ctx.getBean("helloProxy");

ti=(TargetInterface)ctx.getBean("helloAdvisorProxy");

ti.hello("lisi");

ti.nihao("lisi");


结果:

before execute

hello :lisi

你好 :lisi


   2.
RegexpMethodPointcutAdvisor,使用正则来编写pointcut表达式。
 

3.ControlFlowPointcut

用来判断某个方法中,是否要求目标对象执行某个方法,在执行时期动态决定是否介入Advice来提供服务,所以这是动态的PointCut功能

public class Some implements ApplicationContextAware{

      private TargetInterface target;

      
         public
 void setApplicationContext(ApplicationContext 

      applicationContext)throws BeansException {

         target=(TargetInterface)applicationContext.getBean("");

      }

      public void helloEverybody(){

         target.hello("wangwu");

         target.nihao("qw");

      }

      public void hello(){

         System.out.println("hello!");

      }

}
 
 
Some some=(Some)ctx.getBean("some");

boolean flag=true;

if(flag){

   some.helloEverybody();

}else{

   some.hello();

}


PointCut
Spring中的PointCut是实现PointCut接口来实现的:
 

public interface Pointcut {

   ClassFilter getClassFilter();

   MethodMatcher getMethodMatcher();

   Pointcut TRUE = TruePointcut.INSTANCE;

}

TruePointcutPointCut的简单实现,传回的ClassFilterClassFilter.TRUE,传回的MethodMatcherMethodMatcher.TRUE;


      ClassFilter决定一个类是否要应用Advicematches决定传入的类是否符合PointCur的定义。

   public
 interface ClassFilter {

   boolean matches(Class clazz);

   ClassFilter TRUE = TrueClassFilter.INSTANCE;

}

MethodMatcher决定某个方法是否要应用Advice


   public
 interface MethodMatcher {

   boolean matches(Method method, Class targetClass);

   boolean isRuntime();

   boolean matches(Method method, Class targetClass, Object[] args);

   MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;

}
 

如果是静态的PointCut,比如前面的NameMatchMethodPointcutAdvisor 

RegexpMethodPointcutAdvisor,则执行第一个方法,isRuntime返回FALSE,否则执行第二个方法,isRuntime返回true

如果有多个PointCut,还可以对它进行交集、并集的操作,通过ComposablePointcut类,可以操作它的intersectionunion方法。
 

Introduction

是一种特殊的Advice,从行为上来看,它不像前面的BeforeAfter等,在方法前后介入服务,而是直接介入整个对象的行为,就好像凭空多了一些可操作的行为,为对象动态加入(Mixin)原先所没有的职责。

<!-- Mixin -->

<!-- 原来的 -->

<bean id="someService" class="onlyfun.caterpillar.Some" /> 

<!-- 新加的 -->

<bean id="otherIntroduction" 

   class="onlyfun.caterpillar.OtherIntroduction" /> 


   <
bean id="introductionAdvisor" class=

"org.springframework.aop.support.DefaultIntroductionAdvisor">

   <constructor-arg ref="otherIntroduction" /> 

   <constructor-arg value="onlyfun.caterpillar.IOther" /> 
 
</bean>

   <
bean id="proxyFactoryBean" 

class="org.springframework.aop.framework.ProxyFactoryBean">

   <property name="proxyInterfaces" 

   value="onlyfun.caterpillar.ISome" /> 

   <property name="target" ref="someService" />  

    <property name="interceptorNames">

      <list>

         <value>introductionAdvisor</value> 

     </list>

     </property>

 </bean>

ApplicationContext ctx = new 

ClassPathXmlApplicationContext("Aop.xml");

ISome some=(ISome)ctx.getBean("proxyFactoryBean");

some.doSome();

//看起来像是增加了职责

((IOther)some).doOther();
结果:

原来对象的职责。。。

增加的职责...
 

Autoproxing

自动代理可以不用为每一个目标对象手动代理对象,使用自动代理,可以通过Bean名称或是Pointcut对比,自动为符合对比条件的目标对象建立代理对象。

1.BeanNameAutoProxyCreator

看一下前面的配置:

<bean id="before" class="com.bhsc.AOP.BeforeAdvicesTest"></bean>

<bean id="target" 

class="com.bhsc.AOP.target.TargetImple"></bean>

<bean id="helloProxy" 

class="org.springframework.aop.framework.ProxyFactoryBean">

   <property name="proxyInterfaces" 

value="com.bhsc.AOP.target.TargetInterface"/>

   <property name="target" ref="target"/>

   <property name="interceptorNames">

      <list>

         <value>before</value>

      </list>

   </property>

</bean>

不仅要定于Advicetarget,还要定义一个代理对象,配置接口,target等,如果应用比较大,那么一个个配置是很麻烦的,PointcutAdvisor的定义只是对切入点更准确的定义,并不能解决配置繁琐的问题(NameMatchMethodPointcutAdvisor),不过Spring提供了自动代理,可以更加简单的配置。

比如,我们为Bean取好名称,xxxService,这样,就可以使用BeanNameAutoProxyCreator配置:

<!-- 自动代理 -->

<bean id="introductionProxyCreator" 

   class="org.springframework.

aop.framework.autoproxy.BeanNameAutoProxyCreator">

   <property name="interceptorNames" value="introductionAdvisor" />  

   <property name="beanNames">

      <list>

         <value>*Service</value> 

     </list>

   </property>

</bean>

ISome someService=(ISome)ctx.getBean("someService");

someService.doSome();

((IOther)someService).doOther();

以后只要新增
 

2.DefaultAdvisorAutoProxyCreator:自动搜寻

 
 
 
 
 
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多