Spring中对于非匹配的子类的方法拦截问题

     在上一篇中,说明了对于非匹配的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

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

邮箱地址不会被公开。 必填项已用*标注