您现在的位置是:首页 >学无止境 >Spring Advice是如何转换为MethodInterceptor网站首页学无止境

Spring Advice是如何转换为MethodInterceptor

路人丁. 2024-06-14 17:17:43
简介Spring Advice是如何转换为MethodInterceptor

前文我们探讨了AOP中几个重要的概率,Advice作为通知抽象的标记接口,有多种实现类,在最终织入到Joinpoint中后都会转换为MethodInterceptor形成拦截器链,以便于统一调用invoke方法,那么这个过程是如何做到的呢?我们接下来就详细分析其过程。

Advice的多种子接口


五种Advice具体实现,他们都继承了抽象的AbstractAspectJAdvice
image.png
从名称上不难猜测这几个具体实现分别对应解析@Aspect注解配置类中的@Before@After@AfterReturning@AfterThrowing@Around五种类型的通知注解。

Advice转换为MethodInterceptor的适配器

image.png
AdvisorAdapter是用来将封装在Advisor中的具体Advice通知,根据其具体通知类型转换为MethodInterceptor,因为只有这三种类型需要转换,故只有三种实现(AroundAdvice实际上已经实现了MethodInterceptor不用转换)。我们具体看看是如何转换的:

class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof AfterReturningAdvice);
	}
	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
        
        // 利用AfterReturningAdviceInterceptor对通知进行封装
		return new AfterReturningAdviceInterceptor(advice);
	}
}

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
	private final AfterReturningAdvice advice;
	
    public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}
	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
        // 继续执行拦截器链或目标方法
		Object retVal = mi.proceed();
        // 返回后调用通知方法
		this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
		return retVal;
	}
}

所以这里必然对应着三种静态代理类
image.png

具体在何时被转换的呢?

我们根据猜测已经看到了类结构图,猜想了其具体实现原理,那么在什么时候被转换为拦截器链的呢?猜想两个时机可能被创建,要么在创建代理对象,要么在方法执行的时候去封装。

  1. 在创建代理对象后方法不一定会被调用执行,那么这会损耗性能,同时我们知道所有的代理对象都可以转换为Advised,并可以调用Advised#advice()方法继续添加通知(未冻结)。
  2. 从这个角度出发,不难猜测真正创建拦截器链必然是在方法的执行时才会创建,并且不会缓存(若缓存了那么新加的通知就不会生效),如果缓存必须在修改通知时清除缓存。

我们以jdk动态代理为例,分析JdkDynamicAopProxy,它实现了InvocationHandler,在invoke方法中肯定有如何创建拦截器链的方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Object target = null;

    try {
        // ... 省略部分代码....
        Object retVal;

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // Get the interception chain for this method.
        // 创建拦截器链(通过Advised配置)
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        if (chain.isEmpty()) {
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        } else {
            // We need to create a method invocation...
            MethodInvocation invocation =
                new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // Proceed to the joinpoint through the interceptor chain.
            retVal = invocation.proceed();
        }
        // ...省略部分代码...
        return retVal;
    }
    
}

果然符合猜测结果,是在方法执行时才创建的拦截器链,那么继续确认是否有缓存存在呢?

// 在Advised的抽象实现AdvisedSupport中
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    List<Object> cached = this.methodCache.get(cacheKey);
    if (cached == null) {
        // 获取拦截器链
        cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
            this, method, targetClass);
        this.methodCache.put(cacheKey, cached);
    }
    return cached;
}

他娘的,居然有缓存,那么说明在添加通知方法(Advised#addAdvice())的时候必然会清除缓存,否则导致新增通知无效。

private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
    Assert.notNull(advisor, "Advisor must not be null");
    if (isFrozen()) {
        throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
    }
    if (pos > this.advisors.size()) {
        throw new IllegalArgumentException("Illegal position " + pos + " in advisor list with size " + this.advisors.size());
    }
    this.advisors.add(pos, advisor);
    adviceChanged();
}
// 清除缓存
protected void adviceChanged() {
    this.methodCache.clear();
}

果然是在添加通知的时候有回调清除方法对应的拦截器缓存,这里印证了猜想。
同时,在上面创建拦截器方法我们看到是使用工厂类DefaultAdvisorChainFactory的方式来创建的拦截器链,接下来继续分析到底是如何创建拦截器链,也就是如何从Advice转换为了MethodInterceptor

DefaultAdvisorChainFactory拦截器链创建工厂

该类是AdvisorChainFactory接口的唯一实现,封装了如何从Advised配置中将Advisor中的Advice转换为拦截器。

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

	@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

 
        // 全局适配器注册中心(注册了上面说道的三个转换适配器AdvisorAdaptor)
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        // 取出配置中的Advisor
		Advisor[] advisors = config.getAdvisors();
		List<Object> interceptorList = new ArrayList<>(advisors.length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		Boolean hasIntroductions = null;

		for (Advisor advisor : advisors) {
            // 分类型处理
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                // 类是否满足等
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					boolean match;
					if (mm instanceof IntroductionAwareMethodMatcher) {
						if (hasIntroductions == null) {
							hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
						}
                        // 方法是否满足切点表达式
						match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
					} else {
                        // 方法是否满足切点表达式
						match = mm.matches(method, actualClass);
					}
					if (match) {
                        // 使用适配器进行转换
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
                            // 添加到拦截器链中
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			} else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    
                    // 匹配成功后并转化为MethodInterceptor,最后添加到拦截器链中
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			} else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

	/**
	 * Determine whether the Advisors contain matching introductions.
	 */
	private static boolean hasMatchingIntroductions(Advisor[] advisors, Class<?> actualClass) {
		for (Advisor advisor : advisors) {
			if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (ia.getClassFilter().matches(actualClass)) {
					return true;
				}
			}
		}
		return false;
	}
}

这里运用到AdvisorAdapterRegistry全局适配器注册中心,我们继续看看注册的适配器

适配器注册中心AdvisorAdapterRegistry

前面我们说了三类通知的适配器如何将Advice转换为MethodInterceptor,这里就是这些适配器的用武之地。

public final class GlobalAdvisorAdapterRegistry {

	private GlobalAdvisorAdapterRegistry() {
	}

	private static AdvisorAdapterRegistry instance = new DefaultAdvisorAdapterRegistry();
 
	public static AdvisorAdapterRegistry getInstance() {
		return instance;
	}
}
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
	private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
	// 注册了上文所说的适配器
	public DefaultAdvisorAdapterRegistry() {
		registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
		registerAdvisorAdapter(new AfterReturningAdviceAdapter());
		registerAdvisorAdapter(new ThrowsAdviceAdapter());
	}

	@Override
	public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
		if (adviceObject instanceof Advisor) {
			return (Advisor) adviceObject;
		}
		if (!(adviceObject instanceof Advice)) {
			throw new UnknownAdviceTypeException(adviceObject);
		}
		Advice advice = (Advice) adviceObject;
		if (advice instanceof MethodInterceptor) {
			// So well-known it doesn't even need an adapter.
			return new DefaultPointcutAdvisor(advice);
		}
		for (AdvisorAdapter adapter : this.adapters) {
			// Check that it is supported.
			if (adapter.supportsAdvice(advice)) {
				return new DefaultPointcutAdvisor(advice);
			}
		}
		throw new UnknownAdviceTypeException(advice);
	}
    // 转换为MethodInterceptor
	@Override
	public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
		List<MethodInterceptor> interceptors = new ArrayList<>(3);
		Advice advice = advisor.getAdvice();
        
        // 本身实现了MethodInterceptor,如@Around,@After
		if (advice instanceof MethodInterceptor) {
			interceptors.add((MethodInterceptor) advice);
		}
        // 对于注册的三种Advice
		for (AdvisorAdapter adapter : this.adapters) {
			if (adapter.supportsAdvice(advice)) {
				interceptors.add(adapter.getInterceptor(advisor));
			}
		}
		if (interceptors.isEmpty()) {
			throw new UnknownAdviceTypeException(advisor.getAdvice());
		}
		return interceptors.toArray(new MethodInterceptor[0]);
	}

	@Override
	public void registerAdvisorAdapter(AdvisorAdapter adapter) {
		this.adapters.add(adapter);
	}
}

为什么只注册了三种AdvisorAdapter适配器

我们在前面讨论了共有五种通知类型,除了@Around还有@Before@After@AfterReturning@AfterThrowing四种,这里为什么只有三种适配器呢,我们看看@After其也实现了MethodInterceptor,这里只有三种适配器。

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	public AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}

	@Override
	@Nullable
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
			return mi.proceed();
		} finally {
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}
}

至此,整个链路就串联起来了,从Advice到MethodInterceptor,spring通过层层封装,配置等方式,将多种通知类型最用运用到代理对象上,结合动态代理使代理对象得到通知增强。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。