Spring 运用 pointcut 和 advisor 对特定的方法进行切面编程

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

 

上一个例子演示了对特定的bean中的所有的方法进行面向切面编程,包括了 before , after , after throwing, around 几种形式:

如果想对一个bean中的特定方法进行切面编程,而不是所有的方法,就需要设置pointcut了,pointcut允许拦截一个方法通过 方法名 ,一个 pointcut必须和一个advisor想关联。

一般有以下配置组成:

1:advice  在方法执行前(before)后(after)做出相应的响应。通常是定义一些实现接口的类,然后实现相应的方法,比如:before  对应的实现MethodBeforeAdvice接口   ,  after对应的实现AfterReturningAdvice   , around对应的实现MethodInterceptor接口 ,  after throwing 对应的实现:ThrowsAdvice 接口, 实现对应的接口的方法即可。


Pointcut 运用的例子:

一:能够通过以下两种方式匹配相应的方法:
   1:通过name(名称)匹配。
   2:通过正则表达式匹配。

二:通过名称匹配:
1:通过pointcut 和 advisor 拦截printName方法:创建一个org.springframework.aop.support.NameMatchMethodPointcut的切点bean  ----->   bookPointcut   即切点(pointcut) 其属性 mappedName  定义了 需要拦截的方法,就是切点。如下:
[html]   view plain copy
  1. <!-- define  a  pointcut -->  
  2.    
  3.  <bean id="bookPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">  
  4.    <property name="mappedName" value="printName" />  
  5.  </bean>  

2:定义一个advice 相当于 对切点所做的操作, 根据advice的拦截位置需要实现相应的接口,比如: MethodInterceptor 是around对应的接口。
配置片段如下:
[html]   view plain copy
  1. <!-- around  method -->  
  2. bean id="aroundMethod"  class="com.myapp.core.aop.advice.AroundMethod" />   

对应的类:
[java]   view plain copy
  1. package com.myapp.core.aop.advice;  
  2.   
  3. import java.util.Arrays;  
  4.   
  5. import org.aopalliance.intercept.MethodInterceptor;  
  6. import org.aopalliance.intercept.MethodInvocation;  
  7.   
  8. public class AroundMethod  implements MethodInterceptor{  
  9.   
  10.     @Override  
  11.     public Object invoke(MethodInvocation methodInvocation) throws Throwable {  
  12.         // TODO Auto-generated method stub  
  13.           
  14.         System.out.println("method  name:" + methodInvocation.getMethod().getName());  
  15.           
  16.         System.out.println("method  arguments" + Arrays.toString(methodInvocation.getArguments()));  
  17.           
  18.         System.out.println("Around  method : before ");  
  19.           
  20.         try{  
  21.               
  22.             Object result = methodInvocation.proceed();  
  23.               
  24.             System.out.println("Around method : after ");  
  25.             return  result;  
  26.               
  27.         }catch(IllegalArgumentException e){  
  28.               
  29.             System.out.println("Around method : throw  an  exception ");  
  30.             throw  e;  
  31.         }  
  32.     }  
  33.   
  34. }  
以上就是一个advice对应的类:

3:定义一个 advisor 
advisor 是org.springframework.aop.support.DefaultPointcutAdvisor的bean里面有对应的属性:
包括:
pointcut  相当于以上定义的:bookPointcut
advice相当于以上定义的:aroundMethod

所以advisor对应的配置如下:
[html]   view plain copy
  1. <!-- define a advisor -->  
  2.    <bean id="bookAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
  3.     <property name="pointcut"  ref="bookPointcut"/>  
  4.     <property name="advice" ref="aroundMethod"></property>  
  5.    </bean>  
  6.      

其他部分不变:

完整的配置文件如下:
[html]   view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  6.   
  7.   <!-- more bean definitions for data access objects go here -->  
  8.      
  9.     <bean id="book" class="com.myapp.core.aop.advice.Book">  
  10.         <property name="name" value="Effective java" />  
  11.         <property name="url" value="www.google.cn"/>  
  12.         <property name="pages" value="300" />  
  13.     </bean>  
  14.         <!-- around  method -->  
  15.    <bean id="aroundMethod"  class="com.myapp.core.aop.advice.AroundMethod" />   
  16.       
  17.     <!-- define  a  pointcut -->  
  18.       
  19.     <bean id="bookPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">  
  20.       <property name="mappedName" value="printName" />  
  21.     </bean>  
  22.       
  23.     <!-- define a advisor -->  
  24.     <bean id="bookAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
  25.      <property name="pointcut"  ref="bookPointcut"/>  
  26.      <property name="advice" ref="aroundMethod"></property>  
  27.     </bean>  
  28.     <bean id="bookProxy" class="org.springframework.aop.framework.ProxyFactoryBean" >  
  29.      <property name="target" ref="book"/>  
  30.        
  31.      <property name="interceptorNames">  
  32.        <list>  
  33.         
  34.         <value>bookAdvisor</value>  
  35.        </list>  
  36.      </property>  
  37.       
  38.      </bean>  
  39. </beans>  


对应的测试类:
[java]   view plain copy
  1. package com.myapp.core.aop.advice;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. public class MainTest {  
  7.    public static void main(String[] args) {  
  8.         
  9.        ApplicationContext  context  = new  ClassPathXmlApplicationContext("resource/aop.xml");  
  10.          
  11.        Book   book  =   (Book) context.getBean("bookProxy");  
  12.          
  13.        System.out.println("---------------------");  
  14.          
  15.        book.printName();  
  16.          
  17.        System.out.println("---------------------");  
  18.          
  19.        book.printUrl();  
  20.          
  21.        System.out.println("----------------------");  
  22.          
  23.        try{  
  24.              
  25.           book.printThrowException();  
  26.              
  27.        }catch(Exception e){  
  28.          //  e.printStackTrace();  
  29.        }  
  30.          
  31.          
  32. }  
  33. }  

测试结果:
只有在调用printName方法的时候才应用around的,其他方法不应用around,所以输出结果如下:
[plain]   view plain copy
  1. 三月 20, 2013 5:37:23 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh  
  2. INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@eb67e8: startup date [Wed Mar 20 17:37:23 CST 2013]; root of context hierarchy  
  3. 三月 20, 2013 5:37:23 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions  
  4. INFO: Loading XML bean definitions from class path resource [resource/aop.xml]  
  5. 三月 20, 2013 5:37:23 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons  
  6. INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@157985: defining beans [book,aroundMethod,bookPointcut,bookAdvisor,bookProxy]; root of factory hierarchy  
  7. ---------------------  
  8. method  name:printName  
  9. method  arguments[]  
  10. Around  method : before   
  11. Book name Effective java  
  12. Around method : after   
  13. ---------------------  
  14. Book URL www.google.cn  
  15. ----------------------  

只有在printName方法上作用了around,其他方法没有调用,over。
 

9.5.3 容器中的织入器--ProxyFactoryBean(1)

虽然使用ProxyFactory,可以让我们能够独立于Spring的IoC容器之外来使用Spring的AOP支持,但是,将Spring AOP与Spring的IoC容器支持相结合,才是发挥Spring AOP更大作用的最佳途径。通过结合Spring的IoC容器,我们可以在容器中对Pointcut和Advice等进行管理,即使它们依赖于其他业务对象,也可以很容易地注入其中。

在IoC容器中,使用org.springframework.aop.framework.ProxyFactoryBean作为织入器,它的使用与ProxyFactory无太大差别。不过在演示ProxyFactoryBean的使用之前,我们有必要在看清了ProxyFactory本质的前提下,进一步弄明白ProxyFactoryBean的本质。

1. ProxyFactoryBean的本质

对于ProxyFactoryBean,我们应该这样断词,即Proxy+FactoryBean,而不是ProxyFactory+ Bean。也就是说,ProxyFactoryBean本质上是一个用来生产Proxy的FactoryBean。还记得IoC容器中的FactoryBean的作用吧?如果容器中的某个对象持有某个FactoryBean的引用,它取得的不是FactoryBean本身,而是FactoryBean的getObject()方法所返回的对象。所以,如果容器中某个对象依赖于ProxyFactoryBean,那么它将会使用到ProxyFactoryBean的getObject()方法所返回的代理对象,这就是ProxyFactryBean得以在容器中游刃有余的原因。

要让ProxyFactoryBean的getObject()方法返回相应目标对象类的代理对象其实很简单。因为ProxyFactoryBean继承了与ProxyFactory共有的父类ProxyCreatorSupport,而ProxyCreator- Support基本上已经把要做的事情(如设置目标对象、配置其他部件、生成对应的AopProxy等)全部完成了。我们只需在ProxyFactoryBean的getObject()方法中通过父类的createAopProxy()取得相应的AopProxy,然后"return AopProxy.getProxy()"即可。

因为涉及FactoryBean,所以在实现getObject()时,逻辑上还得点缀一下。我们来看ProxyFac- toryBean的getObject()定义(见代码清单9-26)。

代码清单9-26 ProxyFactoryBean的getObject()方法逻辑

  
  
  1. public Object getObject() throws BeansException {  
  2.     initializeAdvisorChain();  
  3.     if (isSingleton()) {  
  4.         return getSingletonInstance();  
  5.     }  
  6.     else   
  7.     {  
  8.     if (this.targetName == null)   
  9.     {  
  10.         logger.warn("Using non-singleton proxies 
    with singleton targets is often undesirable."
     +?  
  11.         "Enable prototype proxies by setting the 
    'targetName' property."
    );  
  12.     }  
  13.     return newPrototypeInstance();  
  14.     }  

FactoryBean定义中要求标明返回的对象是以singleton的scope返回,还是以prototype的scope返回。所以,得针对这两种情况分别返回不同的代理对象,以满足FactoryBean的isSingleton()方法的语义。

如果将ProxyFactoryBean的singleton属性设置为true,则ProxyFactoryBean在第一次生成代理对象之后,会通过内部实例变量singletonInstance(Object类型)缓存生成的代理对象。之后,所有的请求将会返回这一缓存实例,从而满足singleton的语义。反之,如果将ProxyFactoryBean的singleton属性设置为false,那么,ProxyFactoryBean每次都会重新检测各项设置,并为当前调用准备一套新的环境,然后再根据最新的环境数据,返回一个新的代理对象。因此,如果singleton属性为false,在生成代理对象的性能上存在损失。如果非要这么做,请确保有充足的理由。singleton默认值为true,即返回同一个代理对象实例。

如果对ProxyFactoryBean的细节感兴趣,可以读一下ProxyFactoryBean的代码。

2. ProxyFactoryBean的使用

与ProxyFactory一样,通过ProxyFactoryBean,我们可以在生成目标对象的代理对象的时候,指定使用基于接口的代理还是基于类的代理方式,而且,因为它们全部继承自同一个父类,大部分可设置项目都相同。不过,ProxyFactoryBean在继承了父类ProxyCreatorSupport的所有配置属性之外,还添加了几个自己独有的,如下所示。

proxyInterfaces。如果我们要采用基于接口的代理方式,那么需要通过该属性配置相应的接口类型,这是一个Collection类型实例,所以我们可以通过配置元素<list>来指定一个或者多个接口类型。实际上,这与通过Interfaces属性指定接口类型是等效的,我们完全可以随个人喜好来使用,虽然使用proxyInterfaces可以保持使用上的统一风格。另外,如果目标对象实现了某个或者多个接口,即使我们不通过该属性指定要代理的接口类型,ProxyFactroyBean也可以自动检测到目标对象所实现的接口,并对其进行基于接口的代理。因为ProxyFactoryBean有一个autodetectInterfaces属性,该属性默认值为true,即如果没有明确指定要代理的接口类型,ProxyFactoryBean会自动检测目标对象所实现的接口类型并进行代理。

interceptorNames。通过该属性,我们可以指定多个将要织入到目标对象的Advice、拦截器以及Advisor,而再也不用通过ProxyFactory那样的addAdvice或者addAdvisor方法一个一个地添加了。因为该属性属于Collection类型,所以通常我们会使用配置元素<list>添加需要的拦截器名称。该属性有两个特性需要提及,如以下所述。

如果没有通过相应的设置目标对象的方法明确为ProxyFactoryBean设置目标对象,那么可以在interceptorNames的最后一个元素位置,放置目标对象的bean定义名称。这是个特例,大部分情况下,还是建议明确指定目标对象,而避免这种配置方式。

通过在指定的interceptorNames某个元素名称之后添加*通配符,可以让ProxyFactory- Bean在容器中搜寻符合条件的所有的Advisor并应用到目标对象。这些符合条件的Advisor,Spring参考文档中称之为global advisor。代码清单9-27给出了这种用法的示例。

singleton。因为ProxyFactoryBean本质上是一个FactoryBean,所以我们可以通过singleton属性,指定每次getObject调用是返回同一个代理对象,还是返回一个新的。通常情况下是返回同一个代理对象,即singleton为true。只有在需要返回有状态的代理对象的情况下,才会将singleton设置为false,如使用Introduction的场合。

代码清单9-27 包含*通配符的interceptorNames属性使用示例

  
  
  1. <bean id="proxy"   
  2.     class="org.springframework.aop.framework.ProxyFactoryBean">  
  3.     <property name="target" ref="..."/>  
  4.     <property name="interceptorNames">  
  5.         <list>  
  6.             <value>global*</value>  
  7.         </list>  
  8.     </property>  
  9. </bean>  
  10. <bean id="global_debug" ?  
  11. class="org.springframework.aop.interceptor.DebugInterceptor"/>  
  12. <bean id="global_performance" class="org.
    springframework.aop.interceptor. ?  
  13. PerformanceMonitorInterceptor"/> 

要在容器中通过ProxyFactoryBean使用基于接口的代理方式,通常可以采用代码清单9-28所示的配置方式。

代码清单9-28 通过ProxyFactoryBean使用基于接口的代理方式的配置示例

  
  
  1. <bean id="pointcut" class="org.springframework.aop.
    support.NameMatchMethodPointcut"
    >  
  2.     <property name="mappedName" value="execute"/>  
  3. </bean>  
  4.  
  5. <bean id="performanceInterceptor" class="...
    advice.PerformanceMethodInterceptor"
    >  
  6. </bean>  
  7.  
  8. <bean id="performanceAdvisor" class="org.
    springframework.aop.support.DefaultPointcutAdvisor"
    >  
  9.     <property name="pointcut">  
  10.         <ref bean="pointcut"/>  
  11.     </property>  
  12.     <property name="advice">  
  13.         <ref bean="performanceInterceptor"/>  
  14.     </property>  
  15. </bean>  
  16.  
  17. <bean id="task" class="...MockTask">  
  18. </bean>  
  19.  
  20. <bean id="taskProxy" class="org.springframework.
    aop.framework.ProxyFactoryBean"
    >  
  21.     <property name="target">  
  22.         <ref bean="task"/>  
  23.     </property>  
  24.     <property name="proxyInterfaces">  
  25.         <list>  
  26.             <value>...ITask</value>  
  27.         </list>  
  28.     </property>  
  29.     <property name="interceptorNames">  
  30.         <list>  
  31.             <value>performanceAdvisor</value>  
  32.         </list>  
  33.     </property>  
  34. </bean> 

现在,从Pointcut到Advice再到Advisor,从目标对象到相应的代理对象,全部都由IoC容器统一管理。为ProxyFactoryBean指定目标对象、要代理的接口类型以及相应的Advisor或Advice,ProxyFactoryBean就会返回目标对象的代理对象供调用者使用。我们可以将生成的代理对象直接注入到依赖的主体对象中,但是这里有一个初学者容易犯的错误,就是通常会将目标对象task注入依赖的主体对象,而不是目标对象的代理对象taskProxy。通过之前有关代理模式的讲解,现在应该不会犯这种错误了。将没有织入任何横切逻辑的目标对象,而不是代理对象注入依赖的主体对象,一定不会产生任何拦截效果。为了避免这种问题,如果没有依赖于目标对象的依赖关系,可以将目标对象的bean定义声明为内部bean,这样,就不会出现该引用目标对象代理对象的地方,反而因不慎或者其他原因而引用目标对象本身的情况。代码清单9-29演示了这种好的实践方式。
 
 

9.5.3 容器中的织入器--ProxyFactoryBean(2)

代码清单9-29 使用内部bean定义避免错误的依赖注入引用

  
  
  1. ...  
  2.  
  3. <bean id="taskProxy" class="org.springframework.
    aop.framework.ProxyFactoryBean"
    >  
  4.     <property name="target">  
  5.         <bean class="...MockTask"/>  
  6.     </property>  
  7.     <property name="proxyInterfaces">  
  8.         <list>  
  9.             <value>...ITask</value>  
  10.         </list>  
  11.     </property>  
  12.     <property name="interceptorNames">  
  13.         <list>  
  14.             <value>performanceAdvisor</value>  
  15.         </list>  
  16.     </property>  
  17. </bean> 

因为autodetectInterfaces的默认值为true,如果确认目标对象所实现的接口就是要代理的接口,那么,完全可以省略通过interfaces或者proxyInterfaces明确指定代理接口的配置。代码清单9-29的配置内容可以精简如下:

  
  
  1. ...  
  2.  
  3. <bean id="taskProxy" class="org.springframework.
    aop.framework.ProxyFactoryBean"
    >  
  4.     <property name="target">  
  5.         <bean class="...MockTask"/>  
  6.     </property>  
  7.     <property name="interceptorNames">  
  8.         <list>  
  9.             <value>performanceAdvisor</value>  
  10.         </list>  
  11.     </property>  
  12. </bean> 

如果没有指定要代理的接口类型,并且目标对象也没有实现任何接口,那么,ProxyFactory- Bean会采用基于类的代理方式为目标对象生成代理对象。不过,即使目标对象实现了某些接口,我们也可以强制ProxyFactoryBean采用基于类的代理方式来生成代理对象。与ProxyFactory一样,只要指定proxyTargetClass为true就可以了(见代码清单9-30)。

代码清单9-30 强制ProxyFactoryBean使用基于类的代理方式的配置示例

  
  
  1. ...  
  2.  
  3. <bean id="taskProxy" class="org.springframework.
    aop.framework.ProxyFactoryBean"
    >  
  4.     <property name="target">  
  5.         <bean class="...MockTask"/>  
  6.     </property>  
  7.     <property name="proxyTargetClass">  
  8.         <value>true</value>  
  9.     </property>  
  10.     <property name="interceptorNames">  
  11.         <list>  
  12.             <value>performanceAdvisor</value>  
  13.         </list>  
  14.     </property>  
  15. </bean> 

不过,现在客户端代码不能将代理对象强制转型为ITask,而应该强制转型为目标对象的具体类型,即MockTask,如下所示:

  
  
  1. ApplicationContext ctx = ...;  
  2. // ITask task = (ITask)ctx.getBean("taskProxy");  
  3. // 错误!  
  4.  
  5. MockTask task = (MockTask)ctx.getBean("taskProxy");  
  6. task.execute(null);  
  7. ... 

提示 有时,我们的应用可能需要依赖于第三方库,这些库中可能有些对象是出于简单实用的目的,就是没有进行面向接口编程,自然就没有实现任何接口。而且,我们自己设计和实现的类,可能出于某种目的,也是没有实现接口的必要,这时,就需要通过将proxyTargetClass设置为true来解决代理的问题。

说完了如何通过ProxyFactoryBean生成目标对象的代理对象(使用"基于接口的代理"方式也好,使用"基于类的代理"方式也好)。下面该说一下Introduction的代理了,因为它一直比较特立独行嘛!

为了演示Introduction的织入,我们引入一个ICounter接口定义以及一个简单实现类,然后将这个接口的行为和状态添加到ITask相应实现类中。ICounter接口以及相关实现类定义见代码清单9-31。

代码清单9-31 ICounter接口以及相关实现类定义

  
  
  1. public interface ICounter {  
  2.     void resetCounter();  
  3.     int getCounter();  
  4. }  
  5.  
  6. public class CounterImpl implements ICounter {  
  7.     private int counter;  
  8.       
  9.     public int getCounter() {  
  10.         counter++;  
  11.         return counter;  
  12.     }  
  13.  
  14.     public void resetCounter() {  
  15.         counter = 0;  
  16.     }  

要将ICounter的行为添加到ITask相应实现类中,可以采用代码清单9-32所示的配置。

代码清单9-32 将ICounter行为添加到ITask的配置示例

  
  
  1. <bean id="task" class="...MockTask" singleton="false">  
  2. </bean>  
  3.  
  4. <bean id="introducedTask" class="org.springframework.
    aop.framework.ProxyFactoryBean"
     ?  
  5. singleton="false">  
  6.     <property name="targetName">  
  7.         <value>task</value>  
  8.     </property>  
  9.     <property name="proxyInterfaces">  
  10.         <list>  
  11.             <value>...ITask</value>  
  12.             <value>...ICounter</value>  
  13.         </list>  
  14.     </property>  
  15.     <property name="interceptorNames">  
  16.         <list>  
  17.             <value>introductionInterceptor</value>  
  18.         </list>  
  19.     </property>  
  20. </bean>   
  21.  
  22. <bean id="introductionInterceptor" ?  
  23. class="org.springframework.aop.support.DelegatingIntroductionInterceptor"   
  24. singleton="false">  
  25.     <constructor-arg>  
  26.         <bean class="...CounterImpl">  
  27.         </bean>  
  28.     </constructor-arg>  
  29. </bean> 

请注意,我们将目标对象的bean定义、ProxyFactoryBean的bean定义,以及相应Introduction- Interceptor的bean定义的scope,全部声明为prototype,也就是singleton="false",并且,这种情况下,我们使用的是"taskName"而不是"task"来指定目标对象(使用task通过ref指定prototype类型的依赖会有什么效果,在Spring的IoC容器部分已经讲述过了。)。这样才能保证每次取得的代理对象都持有各自独有的状态和行为,如下是调用执行的代码示例:

  
  
  1. ApplicationContext ctx = new ClassPathXmlApplicationContext("...");  
  2. Object proxy1 = ctx.getBean("introducedTask");  
  3. Object proxy2 = ctx.getBean("introducedTask");  
  4.  
  5. System.out.println(((ICounter)proxy1).getCounter());  
  6. System.out.println(((ICounter)proxy1).getCounter());  
  7. System.out.println(((ICounter)proxy2).getCounter()); 

因为proxy1和proxy2各自拥有独立的状态,所以,输出为:

  
  
  1. 1 
  2. 2 
  3. 1 

我们之前说过,DelegatingIntroductionInterceptor是一个"伪军",如果不是采用prototype的scope为每一个代理对象都分配一个该类型实例,则无法保证各代理对象拥有各自的状态。不过,如果使用DelegatePerTargetObjectIntroductionInterceptor,那么可以共用一个该类型的Advice实例(即使用sigleton的scope),见代码清单9-33。

代码清单9-33 使用DelegatePerTargetObjectIntroductionInterceptor代替Delegating- IntroductionInterceptor后的配置实例

  
  
  1. <bean id="task" class="...MockTask" singleton="false">  
  2. </bean>  
  3.  
  4. <bean id="introducedTask" class="org.springframework.aop.
    framework.ProxyFactoryBean"
     ?  
  5. singleton="false">  
  6.     <property name="target"><ref bean="task"/></property>  
  7.     <property name="proxyInterfaces">  
  8.         <list>  
  9.             <value>...ITask</value>  
  10.             <value>...ICounter</value>  
  11.         </list>  
  12.     </property>  
  13.     <property name="interceptorNames">  
  14.         <list>  
  15.             <value>introductionInterceptor</value>  
  16.         </list>  
  17.     </property>  
  18. </bean>   
  19.  
  20. <bean id="introductionInterceptor" class="org.
    springframework.aop.support. ?  
  21. DelegatePerTargetObjectIntroductionInterceptor">  
  22.     <constructor-arg index="0">  
  23.         <value>...CounterImpl</value>  
  24.     </constructor-arg>  
  25.     <constructor-arg index="1">  
  26.         <value>...ICounter</value>  
  27.     </constructor-arg>  
  28. </bean> 
至于你的自定义IntroductionInterceptor,在应用的时候,请根据情况设置Introduction- Interceptor的scope以保证状态的独立性。有关ProxyFactoryBean的更多配置项细节,请参照对应的Javadoc,这里就不赘述了。我们得加快织入的速度了,毕竟,一个一个地配置ProxyFactoryBean可不是什么令人感到轻松、愉快的事情。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值