spring的AOP2

13 篇文章 0 订阅

 

4.3PointCut 和Advisor

之前定义的Advice都是直接织入至代理的接口执行前后的,或者在执行方法过程中异常发生时织入的。事实上还可以定义更细致的织入时机。Pointcut定义了感兴趣的jointpoint(Advice的应用时机)。在spring中,使用pointcutadvisor提供的pointcut实例,具体结合advice,spring内建的pointcut都有对应的pointcutadvisor。

 

4.3.1NameMatchMethodPointcutAdvisor

Pointcut定义了jointpoint,在spring中使用pointcutadvisor来提供pointcut,结合advice,pointcutAdvisor为advisor的子接口,advisor接口的定义如下:

Public  interface Advisor{

   BooleanisPerInstance();

   AdvicegetAdvice();

}

Public interface PointcutAdvisorextends Advisor{

   PointcutgetPointcut();

}

Org.springfranework.aop.support.NameMatchMethodPointcutAdvisor,这个是最基本的PointcutAdvisor,用以提供spring中静态的pointcut实例,可使用表示式expression指定advice应用目标上的方法名称,或者是用*来指定,例如当hello*表示执行代理对象上以hello作为开头的方法名称时,它都会应用指定的advices。如果不加的话就是该接口的所有方法都会被进行或前或后的插入新代码。

例子:

#IHello

package onlyfun.pointcutadvisor;

 

public interfaceIHello {

public voidhelloNewbie(String name);

public voidhelloMaster(String name);

}

#HelloSpeaker

package onlyfun.pointcutadvisor;

public classHelloSpeaker implements IHello {

   @Override

   public void helloNewbie(String name) {

      // TODO Auto-generated method stub

      System.out.println("helloNewbie name.... :["+name+"]");

   }

   @Override

   public void helloMaster(Stringname){

      // TODO Auto-generated method stub

      System.out.println("helloMaster name ... :["+name+"]");

   }

}

 

#LofAfterAdvisor

package onlyfun.pointcutadvisor;

 

import java.lang.reflect.Method;

import java.util.logging.Level;

import java.util.logging.Logger;

 

import org.springframework.aop.AfterReturningAdvice;

 

public classLogAfterAdvice implements AfterReturningAdvice {

   private Logger logger =  Logger.getLogger(this.getClass().getName());

   @Override

   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

      // TODO Auto-generated method stub

      logger.log(Level.INFO,"method is ending ...["+method+"]");

   }

 

}

#spring-config.xml

<bean id="helloSpeaker"class ="onlyfun.pointcutadvisor.HelloSpeaker"/>

   <bean id = "logAfterAdvice2" class ="onlyfun.pointcutadvisor.LogAfterAdvice"/>

   <bean id = "helloAdvisor" class ="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

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

         <!-- 

            <propertyname = "mappedName">

                <list>

                   <value>*Newbie</value>

                   <value>*Master</value>

                </list>

            </property>

         -->

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

   </bean>   

   <bean id = "helloProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">

      <property name ="proxyInterfaces" value="onlyfun.pointcutadvisor.IHello"/>

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

      <property name ="interceptorNames">

         <list>

            <value>helloAdvisor</value>

         </list>

      </property>

   </bean>

这里的HelloSpeaker需要单独声明一个bean,这样spring容器才会需要时创建一个,不然的话会报错。

这里使用了NameMatchMethodPointcutAdvisor类,mappedName可以映射接口的方法,具体是哪一个,单个或者list列表列出都可以,然后是advice指定由那个advice处理被拦截的程序执行相应服务。mappedName只有列出来的方法在其执行的时候才会被拦截,没有列出的则不会被拦截处理。

#test

package onlyfun.pointcutadvisor;

 

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

public classPointcutAdvisorTest {

 

   public static void main(String[] args) {

      // TODO Auto-generated method stub

      ApplicationContextcontext  = new ClassPathXmlApplicationContext("spring-config.xml");

      IHello hello = (IHello) context.getBean("helloProxy");

      hello.helloNewbie("dudud");

      hello.helloMaster("master dudud");

   }

 

}

 

4.3.2RegExpMethodPointcutAdvisor

另外一种使用正则表达式匹配需要拦截的方法,org.springframework.aop.support.RegExpPointcutAdvisor可以让我们使用regular expression来编写pointcut表达式,使用spring中静态的Pointcut的实例。

正则表达式:.符合任何一个字符, +符合前一个字符一次或者多次, *符合前一个字符零次或多次, \转意字符。

RegexpMethdPointcutAdvisor的pattern属性可是用来匹配要符合的完整类名称(包名)和方法名称,举个例子如onlyfun.caterpillar.IHello下的hello开始的方法名称,可以如:onlyfun\.caterpillar\.IHello\.hello.*

 

这里只要修改一下配置文件即可

 

  <bean id="helloSpeaker" class ="onlyfun.pointcutadvisor.HelloSpeaker"/>

   <bean id = "logAfterAdvice2" class ="onlyfun.pointcutadvisor.LogAfterAdvice"/>

   <bean id ="helloAdvisor" class ="org.springframework.aop.support.RegexpMethodPointcutAdvisor">

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

      <property name ="pattern" value="onlyfun\.pointcutadvisor\.IHello\.hello.*"/>

   </bean>

 

只要作如上修改即可。

 

4.3.4 pointcut接口

   Spring的pointcut接口是通过org.springframework.aop.Pointcut接口来实现的,定义如下:

Package org.springframework.aop;

Public interface Pointcut{

   ClassFiltergetClassFilter();

   MethodMatchergetMethodMatch();

   PointcutTRUE=TruePointcut.INSTANCE;

}

切点:pointcut,classFilter决定一个类是否要执行advice,methodMatcher决定一个方法是否要执行advice,

Pointcut.TRUE返回的是一个TRUEPointcut 实例,其中有:

public ClassFilter getClassFilter() {

      return ClassFilter.TRUE;

   }

   public MethodMatcher getMethodMatcher() {

      return MethodMatcher.TRUE;

   }

#methodMatcher

 

public interfaceMethodMatcher {

   boolean matches(Method method, Class<?> targetClass);

   boolean isRuntime();

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

   MethodMatcher TRUE =TrueMethodMatcher.INSTANCE;

}

一般静态的pointcut都是使用matches第一个方法,而动态的则先需要判断isRuntime,然后再执行第二个matches方法,这个带有参数。(如ControlFlowPointcut).

 

4.3.5

Pointcut的交集和并集操作

如果建立了多个pointcut,而且可以将几个pointcut进行组合,称为另一个pointcuts的定义时,可以对现有的pointcuts对象进行交集intersection,并集union,org.springframework.aop.support.ComposablePointcut是Pointcut的实现类,可以操作它的intersection()、union()方法。

Pointcut pc = newComposablePointcut().union(classFilter).intersection(methodMatcher).intersection(pointcut);

也可以使用org.springframework.aop.support.PointCuts的union方法,处理两个pointcut。

 

package onlyfun.pointcutadvisor;

 

import java.util.List;

 

importorg.springframework.aop.ClassFilter;

importorg.springframework.aop.MethodMatcher;

importorg.springframework.aop.Pointcut;

importorg.springframework.aop.framework.AopConfigException;

importorg.springframework.aop.support.Pointcuts;

 

public class UnionPoint implementsPointcut {

   privatePointcut pointcut;

  

   publicPointcut getPointcut() {

      if(pointcut== null)

      {

         thrownew AopConfigException("no set the pointcut!");

      }

      returnpointcut;

   }

 

   publicvoid setPointcut(Pointcut pointcut) {

      this.pointcut= pointcut;

   }

   publicvoid setPointcut(List pointcuts){

      if(pointcuts== null || pointcuts.size() ==0){

         thrownew AopConfigException("at least to set one pointcut");

      }

      pointcut= (Pointcut) pointcuts.get(0);

      for(inti=1;i<pointcuts.size();i++){

         Pointcutnext = (Pointcut) pointcuts.get(i);

         pointcut= Pointcuts.union(pointcut, next);

      }

   }

   @Override

   publicClassFilter getClassFilter() {

      //TODO Auto-generated method stub

      returngetPointcut().getClassFilter();

   }

 

   @Override

   publicMethodMatcher getMethodMatcher() {

      //TODO Auto-generated method stub

      returngetPointcut().getMethodMatcher();

   } 

}

 

4.4 introduction

在spring中,introduction是一种特殊的advice,从行为上看,他不像beforeAdvice,afteradvice等在方法的前后介入服务,而是直接介入整个对象的行为,就好像整个对象多了一些可以操作的方法,为对象加入了一些新的职责。

在springaop中可以通过实现org.springframework.aop.introductionInterceptor来实现introduction。

IntroductionInterceptor继承自MethodInterceptor,DynamicIntroductionAdvice.

DynamicIntroductionAdvice中:

booleanimplementsInterface(Class<?> intf);

如果返回为true,则是为对象添加了新的行为。而MethodInterceptor接口中是invoke()方法

@Override

   public Objectinvoke(MethodInvocation methodInvocation) throwsThrowable {

      return null;

   }

此时如果要让目标执行额外的方法就不能再使用methodInvocation的proceed()方法。

 

 

这里有DelegatingIntroductionInterceptor这个可是spring对于IntroductionInterceptor接口的实现,方便操作,使用方法类似;

,BeanNameAutoProxyCreator,这个是对于原有代理的升级,可以根据相应的BeanName进行匹配,如

<bean id =”introductionProxyCreator”class =”org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator”>

   <propertyname =”beanNames”>

      <list>

   <value>*Service</value>

</list>

</property>

<propertyname =”interceptorNames” value =”lockAdvisor”/>

  

</bean>

这里的beanNames未相应的target,设置成原来target中含有的可以匹配的形式即可。

/DefaultAdvisorAutoProxyCreator,这里会匹配默认的Advisor.

                具体可以参考《spring2.0技术手册》林信良著。


 

参考例子:

#IHello

package onlyfun.introductioninterceptor;

 

public interfaceISome {

   public void doSome();

}

#Some

package onlyfun.introductioninterceptor;

 

public classSome implementsISome {

 

   @Override

   public void doSome() {

      // TODO Auto-generated method stub

      System.out.println("原来对象的职责");

   }

 

}

#IOther

package onlyfun.introductioninterceptor;

 

public interfaceIOther {

public voiddoOther();

}

#OtherInterceptor

package onlyfun.introductioninterceptor;

 

import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.IntroductionInterceptor;

 

public class OtherIntroduction implements IntroductionInterceptor, IOther{

  

   @Override

   public Objectinvoke(MethodInvocation methodInvocation) throws Throwable {

      // TODO Auto-generated methodstub

      //如果执行的方法来自IOther接口的定义

      if(implementsInterface(methodInvocation.getMethod().getDeclaringClass())){

         //执行额外的mixin行为

         return methodInvocation.getMethod().invoke(this,methodInvocation.getArguments());

        

      }else{

         returnmethodInvocation.proceed();

      }

     

   }

 

   @Override //是否实现外有接口(对象是否引入外有方法)

   public booleanimplementsInterface(Class<?> clazz) {

      // TODO Auto-generated method stub

      returnclazz.isAssignableFrom(IOther.class);

   }

 

   @Override

   public void doOther() {

      // TODO Auto-generated methodstub

      System.out.println("doother operation.....");

   }

 

}

#spring-config2.xml

<?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:aop="http://www.springframework.org/schema/aop" 

    xmlns:tx="http://www.springframework.org/schema/tx" 

    xmlns:context="http://www.springframework.org/schema/context"  

    xsi:schemaLocation=

        http://www.springframework.org/schema/context  

        http://www.springframework.org/schema/context/spring-context-3.0.xsd   

    http://www.springframework.org/schema/beans  

     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 

    http://www.springframework.org/schema/tx  

    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 

    http://www.springframework.org/schema/aop  

     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 

    

 

    <bean id="some" class="onlyfun.introductioninterceptor.Some"/>

   <bean id = "otherIntroduction" class ="onlyfun.introductioninterceptor.OtherIntroduction"/>

   <bean id ="otherAdvisor" class ="org.springframework.aop.support.DefaultIntroductionAdvisor">

      <constructor-arg ref ="otherIntroduction"/>

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

   </bean>

    

   <bean id ="someProxy" class="org.springframework.aop.framework.ProxyFactoryBean">

     

      <property name ="proxyInterfaces" value ="onlyfun.introductioninterceptor.ISome"/>

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

      <property name ="interceptorNames" >

         <list>

            <value>otherAdvisor</value>

         </list>

      </property>

   </bean>

</beans>

#test

ApplicationContext context  = new ClassPathXmlApplicationContext("spring-config2.xml");

     

      ISomesome  = (ISome)context.getBean("someProxy");

      some.doSome();

     

      ((IOther)some).doOther();

 

如果是使用的继承DelegatingIntroductionInterceptor类的话如下:

除了继承该类之外,还需要实现IOther接口,并重写invoke方法。

packageonlyfun.introductioninterceptor;

 

importorg.aopalliance.intercept.MethodInvocation;

importorg.springframework.aop.support.DelegatingIntroductionInterceptor;

 

public class OtherIntroduction2extends DelegatingIntroductionInterceptor implements IOther{

   privatestatic final long serialVersionUID = 1L;

 

   @Override

   publicObject invoke(MethodInvocation mi) throws Throwable {

      //TODO Auto-generated method stub

     

      returnsuper.invoke(mi);

   }

 

   @Override

   publicvoid doOther() {

      //TODO Auto-generated method stub

      System.out.println("doother method ...");

   }

 

}

其他和之前文件一样,再者就是修改一下spring-config2.xml即可。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值