8. Spring 源码解析之AOP代理对象创建过程

创建代理对象过程有两个入口,AbstractAutoProxyCreator#getEarlyBeanReferenceAbstractAutoProxyCreator#postProcessAfterInitialization ,两个调用的时机不通。

通常情况下,是通过AbstractAutoProxyCreator#postProcessAfterInitialization 来创建的代理对象。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}

wrapIfNecessary方法中大致分了三个步骤:

8.1 校验是否是被增强的bean

与后置处理器的前置实例化 postProcessBeforeInstantiation 做了相同的校验,如下:

if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}

这里不再累述。

8.1.1 获取通知和增强器

入口代码如下:

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

里面会获取适合bean的增强器,findEligibleAdvisors 方法来实现的,主要分了两部分,第一部分是获取候选的增强器,第二部分是发现可以应用的的增强器,代码如下:

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

其中findCandidateAdvisors()postProcessBeforeInstantiation 执行一样,这不过是直接从缓存中获取的,如下图:
image
我们主要看看怎么找到适合bean的增强器。

protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

    // 把beanName放入ThreadLocal
	ProxyCreationContext.setCurrentProxiedBeanName(beanName);
	try {
        // 这一步实现
		return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
	}
	finally {
		ProxyCreationContext.setCurrentProxiedBeanName(null);
	}
}

findAdvisorsThatCanApply 中循环每个Advisor,进行匹配处理,代码如下:

for (Advisor candidate : candidateAdvisors) {
	if (candidate instanceof IntroductionAdvisor) {
		// already processed
		continue;
	}
    // 实现
	if (canApply(candidate, clazz, hasIntroductions)) {
		eligibleAdvisors.add(candidate);
	}
}

canApply 方法做了两个准备工作:

  • 获取切点的方法匹配器,用来匹配目标类的方法。
MethodMatcher methodMatcher = pc.getMethodMatcher();
  • 获取所有接口类,放到一个LinkedHashSet
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));

然后循环每个Class,反射获取类的所有方法,然后通过方法匹配器,去匹配每个方法,代码如下:

classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
	Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
	for (Method method : methods) {
		if (introductionAwareMethodMatcher != null ?
				introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
				methodMatcher.matches(method, targetClass)) {
			return true;
		}
	}
}

这里的方法匹配器的匹配过程调用了AspectJ中的实现,具体细节不分析了。

这时候在findAdvisorsThatCanApply 方法后面调用了一个extendAdvisors(eligibleAdvisors) 方法,这个方法的目的是添加一个ExposeInvocationInterceptor.ADVISOR 作为增强器链的开始部分,转化为一个拦截器链。

AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
    advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
    return true;
}

然后把拦截器链进行排序sortAdvisors(eligibleAdvisors);

8.1.2 创建代理对象

根据返回的拦截器链的结果判断是否有代理对象specificInterceptors != DO_NOT_PROXY 有的话,去创建代理对象。

Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors,
    new SingletonTargetSource(bean));

创建代理对象经历了以下几步:

  • 第一步是创建一个代理工厂类 ProxyFactory

    往代理工厂中添加增强器链、目标对象等。

  • 第二步将拦截器链转换成增强器链

Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
 |- Advisor[] commonInterceptors = resolveInterceptorNames()
 |- advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
  • 第三步根据设置的信息,创建一个代理类
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (!IN_NATIVE_IMAGE &&
			(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.");
		}
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

8.2 提前暴露的代理对象

前面还说过,通过AbstractAutoProxyCreator#getEarlyBeanReference 来实现代理类的创建,具体的代理创建过程和前面一样,这里只说明以下为什么要有这样一个接口,参考例子如下:
在这里插入图片描述

根据bean的生命周期中介绍的,A创建实例完成后,在属性注入前,会加入三级缓存的操作,属性注入时,发现依赖B对象 ,这时候B会先创建,当B实例化完成后,属性注入时发现依赖于A,会把A的实例注入进来,会用三级缓存的ObjectFactory.getObject方法获取A实例,这时候,就把A的代理对象注入进来,如果只使用两级缓存,这时候在A实例化后,不知道最终暴露出去的是谁,并且也不能用原来的bean实例做后面的处理动作,比如registerDisposableBeanIfNecessary(beanName, bean, mbd);

下面用两张图说明以下:

在这里插入图片描述

在这里插入图片描述

8.3 代理对象创建过程图解

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值