spring如何判断bean是否需要被代理
- spring在创建完bean原始实例后,需要判断是否需要给当前bean创建代理对象。
- initializeBean时会调用applyBeanPostProcessorsAfterInitialization方法,该方法会调用所有BeanPostProcessor的postProcessAfterInitialization。
- 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;
}
- 先用PointcutAdvisor过滤,true继续
- 判断methodMatcher 是否为TrueMethodMatcher,因为TrueMethodMatcher永远匹配都是true。不是的话继续
- 如果是引入类型的methodMatcher则强转,这里也不讨论
- 查找当前类及其祖宗类实现的所有接口
- 遍历这些class。获取每个class方法列表包含从父类继承的的方法。接着调用2个参数的methodMatcher#matches方法,如果为true则返回,false则接着循环。