[Spring]Spring AOP创建动态代理的过程

Spring AOP的大致流程

我们在之前的2章中,知晓了Spring AOPBeanPostProcessor的几个关键接口做了介入,分为几个关键点:

  1. 将切面类进行解析成advisors,其中包括解析XML和被@Aspect注解标注的Java切面类.
  2. 在初始化Bean的阶段,将advisors对当前Bean进行筛选,获取到当前Bean匹配的advisors.
  3. 进行动态代理类的创建.

今天,我们就来看看动态代理类在Spring AOP中是怎样去创建出来的.

创建动态代理的入口:wrapIfNecessary

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	// beanName不为空,并且存在于targetSourcedBeans中,也就是自定义的TargetSource被解析过了
	if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	// 如果Bean为advisedBeans,也不需要被代理
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	// isInfrastructureClass和shouldSkip的作用:
	// 识别切面类,加载切面类成advisors
	// 为什么又执行一次是因为存在循环依赖的情况下无法加载advisor
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	// 返回匹配当前Bean的所有Advice、Advisor、Interceptor
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		// 创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息
		Object proxy = createProxy(
				bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
		this.proxyTypes.put(cacheKey, proxy.getClass());
		return proxy;
	}
	// 下次代理的时候直接从缓存拿出判断,不需要重复代理
	this.advisedBeans.put(cacheKey, Boolean.FALSE);
	return bean;
}
复制代码
  1. targetSourcedBeans存储了用户自定义的targetSource,这部分的bean在org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation中已经进行了createProxy的处理,所以在自动化代理的环节中,要过滤掉这部分的bean.
  2. advisedBeans存储了已经被Spring AOP处理过的bean,这部分的bean也是需要进行过滤的.
  3. 进行isInfrastructureClassshouldSkip的处理,这两个方法在之前的文章已经做了详细的解析,它们的主要作用是:识别切面类、解析切面类。之所以再重复调用一次,是为了收尾的工作.
  4. getAdvicesAndAdvisorsForBean获取当前bean匹配的advisors.
  5. 将当前bean缓存到advisedBeans,创建动态代理-createProxy,缓存proxyType. 这里无论是否能获取到bean的advisors,都会做缓存到advisedBeans的步骤.已确保不重复处理同一个bean.

创建动态代理:createProxy

  • org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
		@Nullable Object[] specificInterceptors, TargetSource targetSource) {
	// 如果beanFactory是ConfigurableListableBeanFactory的类型,暴露目标类
	if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
		AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
	}
	// 创建一个ProxyFactory,当前ProxyCreator在创建代理时,将需要用到的字段赋值到ProxyFactory中去
	ProxyFactory proxyFactory = new ProxyFactory();
	// 将当前的AnnotationAwareAspectJAutoProxyCreator对象的属性赋值给ProxyFactory对象
	// 加载一些ProxyConfig
	proxyFactory.copyFrom(this);
	// 处理proxyTargetClass属性
	// 如果希望使用CGLIB进行代理,配置proxyTargetClass为true
	if (!proxyFactory.isProxyTargetClass()) {
		// 检查相应BeanDefinition的“ preserveTargetClass”属性
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		}
		else {
			// 1. 有接口的,调用一次或者多次:proxyFactory.addInterface(ifc);
			// 2. 没有接口的,调用: proxyFactory.setProxyTargetClass(true);
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}
	// 这个方法主要是对前面传递进来的横切逻辑实例进行包装
	// specificInterceptors中有Advice和Interceptor,它们都会被包装成Advisor
	// 调用的先后顺序,通过方法中的applyCommonInterceptorsFirst参数进行设置
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	proxyFactory.addAdvisors(advisors);
	proxyFactory.setTargetSource(targetSource);
	// 扩展实现,子类可以定制proxyFactory
	customizeProxyFactory(proxyFactory);

	proxyFactory.setFrozen(this.freezeProxy);
	// 设置preFiltered的属性值,默认为false.子类:AbstractAdvisorAutoProxyCreator修改为true
	// preFiltered字段的意思是:是否为特定目标类筛选Advisor
	// 该字段和DefaultAdvisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice获取所有的Advisors
	// CglibAopProxy和JdkDynamicAopProxy都会调用此方法,然后递归执行所有的advisor
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}

	return proxyFactory.getProxy(getProxyClassLoader());
}
复制代码
  1. 如果当前的beanFactory属于ConfigurableListableBeanFactory类型,给当前bean对应的BeanDefinition设置上属性”originalTargetClass”为targetClass.
  2. 先new一个ProxyFactory实例,并根据AnnotationAwareAspectJAutoProxyCreator的配置进行proxyTargetClassoptimizeexposeProxyfrozenopaque的属性设置.
  3. Spring不仅提供了对所有bean生效的proxyTargetClass设置,也提供了对单个bean的动态代理配置preserveTargetClass.
  4. 调用buildAdvisors对specificInterceptors进行适配,封装成advisor.有兴趣的可以看看org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#wrap.
  5. 配置advisorstargetSourcefrozen等属性后,进行动态代理的创建.
  6. proxyFactory.getProxy(getProxyClassLoader()),进行动态代理生成.

getProxy: 根据当前bean选择JDK或者CGLIB动态代理

  • org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
	// 首先获取AopProxy对象,其主要有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy
	// 分别用于JDK和CGLIB代理类的生成,其getProxy方法则用于获取具体的代理对象
	return createAopProxy().getProxy(classLoader);
}
复制代码

ProxyFactoryProxyCreatorSupport的子类,在ProxyCreatorSupport中有一个createAopProxy方法,从这里可以获取到具体的代理工厂类.

  • org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
	// 激活AdvisedSupportListener监听器
	if (!this.active) {
		activate();
	}
	return getAopProxyFactory().createAopProxy(this);
}
复制代码
  1. activate方法主要是用来激活AdvisedSupportListener的.
  2. 重点方法是这个:getAopProxyFactory().createAopProxy(this);其中,getAopProxyFactory中存储了一个DefaultAopProxyFactory,它实现了AopProxyFactory接口,接口方法createAopProxy才是真正获取代理工厂的地方.
  • org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		// 如果要代理的类本身就是接口
		// 或者它已经是JDK的代理类(Proxy子类)
		// 使用JDK动态代理
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		// 使用CGLIB动态代理
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		// 接口->JDK动态代理
		return new JdkDynamicAopProxy(config);
	}
}
复制代码

这里就会看到我们很熟悉的一个逻辑:实现了接口的bean,Spring会使用JDK动态代理;否则使用CGLIB代理.

工厂模式:JdkDynamicAopProxy和ObjenesisCglibAopProxy

代理策略选择

由于篇幅的原因,我选择讲解JdkDynamicAopProxy这种模式生成代理的源码解析.

  • org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
public Object getProxy(@Nullable ClassLoader classLoader) {
	if (logger.isTraceEnabled()) {
		logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
	}
	// 获取完整的代理接口
	Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
	findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
	// JdkDynamicAopProxy本身实现了InvocationHandler接口
	return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
复制代码

关于JDK如何生成动态代理的原理,这里不做过多的分析了,这在我之前的博客中有关于JDK和CGLIB生成Proxy的文章,不了解的读者可以去看看:
点我前往
在生成代理之后,Proxy就会调用InvocationHandler.invoke方法,所以关于Spring AOP的代理拦截链执行流程,我们直接去到invoke解析即可。

  • org.springframework.aop.framework.JdkDynamicAopProxy#invoke
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler
复制代码

首先,JdkDynamicAopProxy实现了InvocationHandler接口,动态代理类最终会执行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 {
		// equals方法不需要代理
		if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
			// The target does not implement the equals(Object) method itself.
			return equals(args[0]);
		}
		// hashcode方法不需要代理
		else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
			// The target does not implement the hashCode() method itself.
			return hashCode();
		}
		// 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型
		else if (method.getDeclaringClass() == DecoratingProxy.class) {
			// There is only getDecoratedClass() declared -> dispatch to proxy config.
			return AopProxyUtils.ultimateTargetClass(this.advised);
		}
		// 如果被代理的对象本身实现了Advised接口,则证明该类里面的方法已经被代理了,直接执行即可
		else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
				method.getDeclaringClass().isAssignableFrom(Advised.class)) {
			// Service invocations on ProxyConfig with the proxy config...
			return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
		}

		Object retVal;
		// 是否暴露代理引用
		if (this.advised.exposeProxy) {
			// Make invocation available if necessary.
			oldProxy = AopContext.setCurrentProxy(proxy);
			setProxyContext = true;
		}

		// Get as late as possible to minimize the time we "own" the target,
		// in case it comes from a pool.
		// 获取目标类
		target = targetSource.getTarget();
		Class<?> targetClass = (target != null ? target.getClass() : null);

		// Get the interception chain for this method.
		// 获取方法的拦截链
		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.
		// 如果该方法上没有匹配的拦截器,直接反射调用Method.invoke(target,args)
		if (chain.isEmpty()) {
			// We can skip creating a MethodInvocation: just invoke the target directly
			// Note that the final invoker must be an InvokerInterceptor so we know it does
			// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
			Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
			retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
		}
		else {
			// We need to create a method invocation...
			// 创建ReflectiveMethodInvocation
			MethodInvocation invocation =
					new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
			// Proceed to the joinpoint through the interceptor 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())) {
			// Special case: it returned "this" and the return type of the method
			// is type-compatible. Note that we can't help if the target sets
			// a reference to itself in another returned object.
			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);
		}
	}
}
复制代码
  1. Spring AOP不对equals和hashCode做代理.
  2. 如果当前方法是Spring织入的DecoratingProxy接口中的方法,返回目标对象的class类型.
  3. 如果被代理的对象本身实现了Advised接口,则证明该类里面的方法已经被代理了,直接执行即可
  4. 查看当前配置判断是否暴露代理引用,可以来解决this调用引起的代理失效等问题.
  5. 从targetSource中获取target信息.获取当前method的拦截链路.getInterceptorsAndDynamicInterceptionAdvice会对method的拦截链进行缓存,如果没有缓存,会执行org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice重新对method进行match.
  6. getInterceptorsAndDynamicInterceptionAdvice获取到chain之后,如果chain为空,那么直接激活method.
  7. 如果chain不为空,生成ReflectiveMethodInvocation,从JavaDoc可以知道,这是一个Spring实现了AOP Alliance MethodInvocation接口的类,关键方法:invokeJoinpoint(激活连接点方法)、proceed(执行拦截链逻辑).
  8. 执行proceed.
  9. 处理返回值。包装此返回值(如果有必要作为代理),并验证没有将null作为原语返回。这是什么意思呢:假设方法返回的是int,增强around方法返回了null,这就会报错,因为基础数据类型都有默认值.
  10. 释放资源、重新设置一次代理引用.

这里最关键的的看chain的执行过程,整个Spring AOP拦截链执行的过程采用了一种递归的方式,值得一品.

代理类执行链路

  • org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
	// We start with an index of -1 and increment early.
	// 如果拦截器执行完了,则执行连接点
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}
	// 从0开始执行,每次递归进来都会+1
	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		// 动态匹配:运行时参数是否满足匹配条件
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			// 动态匹配失败,进入下一个拦截器
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		// 执行当前拦截器
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}
复制代码
  1. 在遇到AfterThrowingAfterRetruningAfter这类advice的时候,它们会执行mi.proceed回到chain中.
  2. 回到chain中后,列表索引自增,往下执行下一个advice.
  3. 依次递归,直到遇到Around通知,执行around.
  4. 在around中执行joinPoint.proceed又会回到chain中.
  5. 递归到Before,执行before,然后回到around的后置代码块中.
  6. 回溯到afterafterReturning,如果有异常,执行afterThrowing.
执行流程图

proceed

总结

  • 1. 生成代理类通过工厂模式进行生成,实现接口默认使用JDK动态代理,否则使用CGLIB
  • 2. Spring AOP通过后置处理器的postProcessAfterInitialization方法调用wrapIfNessary对Bean进行代理并替换.
  • 3. 代理类执行拦截链通过chain进行递归proceed来执行每个通知的方法
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享