springAop原理之(四)查找和原始bean关联的Advisor

6 篇文章 0 订阅

spring如何判断bean是否需要被代理

  1. spring在创建完bean原始实例后,需要判断是否需要给当前bean创建代理对象。
  2. initializeBean时会调用applyBeanPostProcessorsAfterInitialization方法,该方法会调用所有BeanPostProcessor的postProcessAfterInitialization。
  3. AbstractAutoProxyCreator就是一个BeanPostProcessor,该类的postProcessAfterInitialization会调用wrapIfNecessary方法,即该bean是否需要被包装成代理对象。是否需要代理原则就是该bean有没有与之相关的Advisor,有就代理(大多数用的是这个类,后面也只讨论这个类生成代理)

注意:有的循环引用的bean没在initializeBean生成代理,而是在被注入到其它bean的时候就已经生成了代理对象。比如:A->B->A,A中有方法被@Transactional标注,则A需要生成A的代理对象,该代理对象是在B注入A时就生成了A的代理(该代理也是走的wrapIfNecessary方法,依旧是下方代码,这里是第一次执行)。然后在A的initializeBean后续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方法要执行是有条件的。earlyProxyReferences存的就是已经生成代理的原始bean。因为A在B中被注入时已经生成了代理,所以这里直接返回原始的bean。initializeBean后续还会有如下代码,这个时候才会获取到A的代理对象。

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);

上面为啥要说有的循环引用的bean?因为如果循环引用的bean A中有方法被@Async标注,则A代理对象并不是通过AbstractAutoProxyCreator生成的,而是通过AsyncAnnotationBeanPostProcessor生成的。所以和异步相关的循环依赖经常会出现BeanCurrentlyInCreationException异常。具体可看之前这篇文章doCreateBean方法中BeanCurrentlyInCreationException解析

spring如何查找所有Advisor源码及如何判断某个bean与之关联的Advisor有哪些

wrapIfNecessary部分源码
// Create proxy if we have advice.
//获取bean有关的Advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
   this.advisedBeans.put(cacheKey, Boolean.TRUE);
   Object proxy = createProxy(
         bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
   this.proxyTypes.put(cacheKey, proxy.getClass());
   return proxy;
}

getAdvicesAndAdvisorsForBean会调用AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  //查找所有的Advisor
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
  //查找所有的Advisor中可应用的某个bean的Advisor
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

findCandidateAdvisors()源码简单可总结为:从容器中获取所有实现了Advisor的类,在加上aspectJ创建的Advisor。
接下来我们看下findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName)源码

protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
   //在ThreadLocal中标记当前beanName
   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
   }
   finally {
     //在ThreadLocal中移除当前beanName
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}

AopUtils findAdvisorsThatCanApply源码分析

public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   if (candidateAdvisors.isEmpty()) {
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new ArrayList<>();
   for (Advisor candidate : candidateAdvisors) {
      //是否为引入切面并且是否能被应用到
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
         eligibleAdvisors.add(candidate);
      }
   }
   //目前用不到IntroductionAdvisor ,所以值为false,看常用的就行
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   for (Advisor candidate : candidateAdvisors) {
      if (candidate instanceof IntroductionAdvisor) {
         // already processed
         continue;
      }
      if (canApply(candidate, clazz, hasIntroductions)) {
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}

接着看canApply方法

	public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
	//这里也不关注引入Advisor
		if (advisor instanceof IntroductionAdvisor) {
			return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
		}
		//只要看PointcutAdvisor就行
		else if (advisor instanceof PointcutAdvisor) {
			PointcutAdvisor pca = (PointcutAdvisor) advisor;
			return canApply(pca.getPointcut(), targetClass, hasIntroductions);
		}
		else {
			// It doesn't have a pointcut so we assume it applies.
			return true;
		}
	}

接着看canApply方法

	public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
		Assert.notNull(pc, "Pointcut must not be null");
		//1
		if (!pc.getClassFilter().matches(targetClass)) {
			return false;
		}
		//2
		MethodMatcher methodMatcher = pc.getMethodMatcher();
		if (methodMatcher == MethodMatcher.TRUE) {
			// No need to iterate the methods if we're matching any method anyway...
			return true;
		}
		//3
		IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
		if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
			introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
		}
		//4
		Set<Class<?>> classes = new LinkedHashSet<>();
		if (!Proxy.isProxyClass(targetClass)) {
			classes.add(ClassUtils.getUserClass(targetClass));
		}
		classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
		//5
		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;
				}
			}
		}

		return false;
	}
  1. 先用PointcutAdvisor过滤,true继续
  2. 判断methodMatcher 是否为TrueMethodMatcher,因为TrueMethodMatcher永远匹配都是true。不是的话继续
  3. 如果是引入类型的methodMatcher则强转,这里也不讨论
  4. 查找当前类及其祖宗类实现的所有接口
  5. 遍历这些class。获取每个class方法列表包含从父类继承的的方法。接着调用2个参数的methodMatcher#matches方法,如果为true则返回,false则接着循环。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值