在spring中,通常在进行事务处理时,我们都会写如一段事务配置文件来保证相应的service类被代理成受事务控制的。那么对于那些没有配置成事务的Service,spring是否也会创建相应的代理类,并且在某些方法上也会追加相应的事务呢。
如下的一段配置:
<aop:config proxy-target-class="true"> <aop:pointcut id="servicePointcut" expression="execution(public * com.greejoy.gtip.component.support.service.BaseService.*(..))"/> <aop:advisor advice-ref="txInterceptor" pointcut-ref="servicePointcut"/> </aop:config>
我们配置了对于在包com.greejoy.gtip.component.support.service下的BaseService类的任何方法均配置一个pointcut,也就是说在这个BaseService下的任何方法均会被拦截,并会通知txInterceptor进行处理。在我们的txInterceptor中处理代码,即打印一句话,表示进入了这个拦截器:
public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("----222"); return invocation.proceed(); }
现在,我们有一个测试类,用于测试指定的类是否已经被spring代理:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Tx2 tx2 = (Tx2) applicationContext.getBean("tx2"); System.out.println(tx2.getClass());
其中类Tx2的声明如下:
public class Tx2 extends BaseService
即Tx2是继承于BaseService的,上面一段代码的输出结果会根据一些变化有所不同。具体描述如下:
- 如果BaseService中没有任何方法(即只是一个标志类),BaseService中没有方法满足我们所声明的pointcut,那么输出结果将会输出class Tx2,表示Tx2没有被spring代理。
- 如果BaseService中有至少一个方法(即使这个方法是ovveride Object类的hascode方法),即可以满足声明中的pointcut,那么输出结果将会输出class Tx2$cglibGeneXXX这样的字样,表示这个Tx2类已经被代理了。
为什么会出现这样的结果,这得归结于spring对于一个bean在初始化时是否应该创建代理的判断了。如下一段代码,spring在创建一个bean之后,会通知beanPostProcessor类来对这个bean作一些附加的处理,其中就会有AspectJAwareAdvisorAutoProxyCreator这个类。这个类会判断当前判断的类是否应该进行创建代理,以及给该对象创建代理。是否应该创建代理,就会根据当前spring容器中注册的pointcut和当前类进行判断,判断是否应该追加代理,相应的逻辑在类AopUtils的canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions)方法上:
MethodMatcher methodMatcher = pc.getMethodMatcher(); IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; …… Set<Class> classes = new HashSet<Class>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher. matches(method, targetClass, hasIntroductions)) || methodMatcher.matches(method, targetClass)) { return true; } } }
如上的类,即会查找当前类的所有方法,并将这些方法和具体的pointcut进行对比,如果其中一个方法满足条件,即会创建代理了。
那么我们来看现在的Tx2类,在BaseService没有方法的时候,Tx2的所有方法归纳如下:
其中可以看出,在11个方法中并没有一个方法满足于pointcut的条件。而如果BaseService有一个方法呢,那么Tx2的所有方法就会有一点不一样了:
这里的12个方法中,新增加了一个方法,为BaseService.x方法(即新增加的方法),这个方法的签名为BaseService.x,而并不是Tx2.x,那么这个签名肯定是满足我们的pointcut判断的(具体判断逻辑请参照相应代码),那么Tx2类就会被创建代理了。
终上所述,对于并没有在pointcut中所直接满足条件的类,如果这些类的父类满足pointcut的断言判断的话,那么也会给这些类创建代理对象进行aop代理。那么这些创建好的对象的自己的方法是否也会受aop Interceptor的影响呢,那就关系到spring在代理创建过程中对方法一级代理的处理问题了。
对于spring如何处理代理子类的代理方法的问题,请点击spring中aop对于非匹配子类方法拦截问题。
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/proxy-created-of-subclass-extended-proxied-class-by-spring.html