在上一篇中,说明了对于非匹配的Tx2类,Spring仍然会创建Tx2的代理类(前提是它的父类是pointcut匹配的),那么aop中如何来判断Tx2的方法是否应该被拦截呢。这得归结于spring在创建代理过程中对于每个方法的匹配问题,如果匹配断言,那么就会被拦截,否则不会被拦截。
如下,BaseService有一个方法x,如下:
public void x() {
System.out.println("x");
}
而,Tx2有一个方法如下:
public void xxxx() {
System.out.println("xxxx");
}
我们通过执行这两个方法来判断它的输出:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Tx2 tx2 = (Tx2) applicationContext.getBean("tx2");
System.out.println(tx2.getClass());
tx2.xxxx();
tx2.x();
输出结果如下:
class Tx2$$EnhancerByCGLIB$$ff70f6ed xxxx ----222 x
即在执行Tx2.xxxx时,并没有执行相应的拦截器,而执行Tx2.x时,即执行了相应的拦截器。这表示Tx2.xxxx并没有匹配断言,而Tx2.x匹配了断言。断言的执行语句是在生成代理的过程中加入的,具体的生成判断语句在类Cglib2AopProxy(本文中使用的是cglib代理)的accept(Method method)方法,该方法会对进行代理的每个方法作判断,判断是否应该加入拦截器的方法,具体的逻辑如下:
// Proxy is not yet available, but that shouldn't matter. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
这一段会针对当前方法取得当前方法的advisor,以判断是否应该加入代理。那么对于Tx2的xxxx方法,是不能匹配pointcut的,所以相应的txInterceptor不会加入到执行链中,而对于Tx2.x方法,是匹配pointcut的(它的匹配方法为BaseService.x),则会加入到执行链中。
如果Tx2复写了BaseService的方法呢,那么结果又会是如何?如下
public void x() {
System.out.println("overide x");
}
输出结果为:
class Tx2$$EnhancerByCGLIB$$f43261e1 xxxx ----222 overide x
即仍然调用了拦截器,这此时Tx2.x方法的签名为Tx2.x(已经不是BaseService.x)了,那么为什么还能匹配pointcut呢?这是因为匹配的具体算法,对于复写方法,它会将当前方法所复写的方法加到一起进行断言判断,如果任一满足的话,就认为匹配断言,而加入拦截方法。具体的逻辑可以参见SignaturePattern的matches(Member joinPointSignature, World world, boolean allowBridgeMethods)方法:
public boolean matches(Member joinPointSignature, World world, boolean allowBridgeMethods) {
……
boolean subjectMatch = true;
boolean wantsAnnotationMatch = wantToMatchAnnotationPattern();
JoinPointSignatureIterator candidateMatches = joinPointSignature.getJoinPointSignatures(world);
while (candidateMatches.hasNext()) {
JoinPointSignature aSig = candidateMatches.next();
FuzzyBoolean matchResult = matchesExactly(aSig, world, allowBridgeMethods, subjectMatch);
if (matchResult.alwaysTrue()) {
return true;
如上的判断逻辑就是判断一个方法是否满足断言了,在判断Tx2.x(复写方法)的时候,它会取得这个方法所有的方法签名,其中就有BaseService.x,那么自然就满足断言,则就会在这个方法追加aop拦截方法了。
当然,如果我们想要使得子类的任何方法都匹配aop拦截的话,我们可以修改这个pointcut:
<aop:pointcut id="servicePointcut" expression="execution(public * com.greejoy.gtip.component.support.service.BaseService+.*(..))"/>
结论:对于在pointcut中并没有匹配的子类,如果子类复写了父类的一个方法,并且这个父类的方法匹配了pointcut,那么子类复写的方法也会追加相应的aop拦截控制,而不是复写的方法则不会被aop拦截了。
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/proxy-method-intercept-of-subclass-extended-proxied-class-by-spring.html