欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring-framework5.0.2 源码阅读笔记 - AOP切面(代码织入阶段)

程序员文章站 2022-06-28 17:42:22
Spring AOP 代码植入阶段注意: 本片博客所展示的代码中,删除了对核心流程以外的代码,为了不影响观看,所以只保留了最核心的代码spring 初始化时序图 (免费克隆)Spring-framework 5.0.2 中文注释源码下载闲聊AOP 主要是分为两个部分,第一部分对需要代理的 bean 《创建代理对象》,存入 IOC容器,则这第二部分就是使用 AOP 阶段了。根据我所提供的时序图中,AOP 部分可以看出,以 JDK 为例,一切动态代理的入口都将会是 InvocationHand...

Spring AOP 代码织入阶段

注意: 本片博客所展示的代码中,删除了对核心流程以外的代码,为了不影响观看,所以只保留了最核心的代码

spring 初始化时序图 (免费克隆)
Spring-framework 5.0.2 中文注释源码下载

闲聊

AOP 主要是分为两个部分,第一部分对需要代理的 bean 《创建代理对象》,存入 IOC容器,则这第二部分就是使用 AOP 阶段了。根据我所提供的时序图中,AOP 部分可以看出,以 JDK 为例,一切动态代理的入口都将会是 InvocationHandler#invoke() 方法,那么在哪里实现了 InvocationHandler 接口呢!回想一下,貌似 JdkDynamicAopProxy类就实现了 InvocationHandler 接口哇,那么为了认证这么一个*”好像“*,就直接进入主题呗

1. 以JDK为例,织入InvocationHandler#invoke()

进入 JdkDynamicAopProxy 类中,找到 invoke(),源码如下:

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

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

	try {
		//equals()方法,具目标对象未实现此方法
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			return equals(args[0]);
		}
		//hashCode()方法,具目标对象未实现此方法
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			return hashCode();
		}
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		//Advised接口或者其父接口中定义的方法,直接反射调用,不应用通知
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		Object retVal;

		if (this.advised.exposeProxy) {
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		//获得目标对象的类
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		//获取可以应用到此方法上的Interceptor列表
		List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

		//如果没有可以应用到此方法的通知(Interceptor),此直接反射调用 method.invoke(target, args)
		if (chain.isEmpty()) {
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			//创建MethodInvocation
			invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			retVal = invocation.proceed();
		}

		// Massage return value if necessary.
		Class<?> returnType = method.getReturnType();
		if (retVal != null && retVal == target &&
				returnType != Object.class && returnType.isInstance(proxy) &&
				!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
			retVal = proxy;
		}
		else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
			throw new AopInvocationException(
					"Null return value from advice does not match primitive return type for: " + method);
		}
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			// Must have come from TargetSource.
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			// Restore old proxy.
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

根据上面的代码和注释,可以简单的看出大致逻辑:
首先获取应用到此方法上的 Interceptor 列表,如果该方法上没有任何通知链,那么直接调用该方法做反射执行,如果有响应的通知存在,那么直接创建 MethodInvocation,调用其 proceed(),其内部依然是执行了 JoinPoint

2. 拦截器链的获取和执行

在这一步中,最为关键的就是获取到 interceptorChian,那么它是如何获取,又是如何执行的,下面开始一一解读:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
	MethodCacheKey cacheKey = new MethodCacheKey(method);
	// 通过方法缓存获取
	List<Object> cached = this.methodCache.get(cacheKey);
	// 如果没有获取到,则尝试使用 AdvisorChainFactory的子类DefaultAdvisorChainFactory 进行获取
	if (cached == null) {
		cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
				this, method, targetClass);
		this.methodCache.put(cacheKey, cached);
	}
	return cached;
}

下面进入 DefaultAdvisorChainFactory 查看 getInterceptorsAndDynamicInterceptionAdvice()

/**
 * 从提供的配置实例config中获取advisor列表,遍历处理这些advisor.如果是IntroductionAdvisor,
 * 则判断此Advisor能否应用到目标类targetClass上.如果是PointcutAdvisor,则判断
 * 此Advisor能否应用到目标方法method上.将满足条件的Advisor通过AdvisorAdaptor转化成Interceptor列表返回.
 */
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
		Advised config, Method method, @Nullable Class<?> targetClass) {

	// This is somewhat tricky... We have to process introductions first,
	// but we need to preserve order in the ultimate list.
	List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
	Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
	//查看是否包含IntroductionAdvisor
	boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
	//这里实际上注册一系列AdvisorAdapter,用于将Advisor转化成MethodInterceptor
	AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

	for (Advisor advisor : config.getAdvisors()) {
		if (advisor instanceof PointcutAdvisor) {
			// Add it conditionally.
			PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
			if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
				//这个地方这两个方法的位置可以互换下
				//将Advisor转化成Interceptor
				MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
				//检查当前advisor的pointcut是否可以匹配当前方法
				MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
				if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
					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)) {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}
		else {
			Interceptor[] interceptors = registry.getInterceptors(advisor);
			interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	return interceptorList;
}

上面的大致逻辑:

  1. 拿到所有的 Advisor,判断,如果类型属于PointcutAdvisor (切入点)那么就将所有的 PointcutAdvisor,转换成 MthodInterceptor 数组,遍历添加到 chain 中,
  2. 如果 Advisor 是属于 IntroductionAdvisor(引入) 类型,那么就将 Advisor 转换成 Interceptor 数组,存入到 chain
  3. 如果既不是 PointcutAdvisor,也不是 IntroductionAdvisor,那直接转换成 Interceptor 数组,加入到 chain

至此,获取 InterceptorChain 的工作就完毕了

3. 获取到interceptorChain不为空的情况

接下来就是使用这个 chain 了,回到 JdkDynamicAopProxy#invoke() 中,如果 chain 不为空的时候,则看一下代码:

if (chain.isEmpty()) {
	Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
	retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}

// is not empty
else {
	//创建 ReflectiveMethodInvocation
	invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
	// 通过得到的拦截器列表,执行各个拦截点
	retVal = invocation.proceed();
}
public Object proceed() throws Throwable {
	//	We start with an index of -1 and increment early.
	//如果Interceptor执行完了,则执行joinPoint
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}

	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	//如果要动态匹配joinPoint
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		//动态匹配:运行时参数是否满足匹配条件
		if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			//动态匹配失败时,略过当前Intercetpor,调用下一个Interceptor, 使用递归方式进行调用,但是不属于同一个拦截器
			return proceed();
		}
	}
	else {
		//执行当前Intercetpor
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

通过以上代码:

  1. 先获取到当前的拦截器,如果该拦截器的类型是动态匹配的类型,那么进入动态匹配类型
    1.1.如果参数满足条件,那么则直接运行拦截器
    1.2.如果不满足,则使用递归,调用下一个拦截器,这里的递归虽然运行的方法是一样的,但是运行的效果有可能完全不相同。
  2. 如果不是动态匹配的拦截器,那么直接执行当前的拦截器

4. 总结

通过以上一顿操作后,AOP 执行其实就是在目标方法被调用的时候,执行代理的 invoke() ,使用预先加载好的拦截器来匹配目标方法是否拥有被拦截的权限。如果有,则将执行配置的切入点,如果没有,则反射调用目标方法。奥里给!!!

接下来最后一篇 MVC 的调用阶段文章会发布,敬请期待!

本文地址:https://blog.csdn.net/qq_38800175/article/details/109530246