Spring 源码笔记-2.8 根据类型寻找 bean--找出所有匹配类型的 beanName

前文

# 源码解析

入参说明

  • includeNonSingletons:是否包括非单例的 bean,比如 prototype scope
  • allowEagerInit:为了这个检查(找出所有匹配类型的 beanName),是否初始化 lazy-init 单例和由 FactoryBeans 创建的对象。此处我们传入的值为 true。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

public static String[] beanNamesForTypeIncludingAncestors(
			ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {

		Assert.notNull(lbf, "ListableBeanFactory must not be null");
  //方法主干还是在这行 getBeanNamesForType
		String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
  //下面的内容就是从 bf 的 parent 中找,
		if (lbf instanceof HierarchicalBeanFactory) {
			HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
			if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
  //此处以 parent 再来调此方法,合并结果。
				String[] parentResult = beanNamesForTypeIncludingAncestors(
						(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
				List<String> resultList = new ArrayList<String>();
				resultList.addAll(Arrays.asList(result));
				for (String beanName : parentResult) {
					if (!resultList.contains(beanName) && !hbf.containsLocalBean(beanName)) {
						resultList.add(beanName);
					}
				}
				result = StringUtils.toStringArray(resultList);
			}
		}
		return result;
	}

看来我们还需要继续深入到 getBeanNamesForType中去一探究竟。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
  //configurationFrozen:判断所有 bean 的 定义元数据是否可以被缓存
  //如果不能缓存 或没type 或不允许急切初始化,则直接查 doGetBeanNamesForType
   if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
      return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
   }
  //否则先查缓存,没有缓存的话再查 doGetBeanNamesForType 并塞入缓存
   Map<Class<?>, String[]> cache =
         (includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
   String[] resolvedBeanNames = cache.get(type);
   if (resolvedBeanNames != null) {
      return resolvedBeanNames;
   }
   resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
  //判断是否缓存安全:依据我们目标class 和当前beanFactory的classLoader是否一致
   if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
      cache.put(type, resolvedBeanNames);
   }
   return resolvedBeanNames;
}

再深入一层到 doGetBeanNamesForType ,其中逻辑外层是遍历所有的 beanName, 对于不是别名的进行处理,处理过程如下(省略了 try-catch ):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//首先获取这个beanName对应的mbd,它的相关定义配置信息
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Only check bean definition if it is complete.
// 不是抽象的
// 并且 允许急切初始化 或 (此bean不需要急切初始化 且(有beanClass 或 不是lazyInit 或 允许急切的类加载,即使是懒惰的初始化bean))
if (!mbd.isAbstract() && (allowEagerInit ||
      ((mbd.hasBeanClass() || !mbd.isLazyInit() || isAllowEagerClassLoading())) &&
            !requiresEagerInitForType(mbd.getFactoryBeanName()))) {
// In case of FactoryBean, match object created by FactoryBean.
//判断是否 FactoryBean
   boolean isFactoryBean = isFactoryBean(beanName, mbd);
   BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
//接下来又是一段非常长的逻辑判断,判断是否匹配
   boolean matchFound =
         (allowEagerInit || !isFactoryBean ||
               (dbd != null && !mbd.isLazyInit()) || containsSingleton(beanName)) &&
         (includeNonSingletons ||
               (dbd != null ? mbd.isSingleton() : isSingleton(beanName))) &&
         isTypeMatch(beanName, type);
   if (!matchFound && isFactoryBean) {
      // In case of FactoryBean, try to match FactoryBean instance itself next.
//如果不匹配,还要试试匹配FactoryBean本身,因为说不好要的就是这个FactoryBean呢
      beanName = FACTORY_BEAN_PREFIX + beanName;
      matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);
   }
   if (matchFound) {
      result.add(beanName);
   }
}

//检查一遍手动的单例集合
//对于 FactoryBean ,如果匹配到它的getObject()满足,就不会继续去匹配它本身
for (String beanName : this.manualSingletonNames) {
				// In case of FactoryBean, match object created by FactoryBean.
				if (isFactoryBean(beanName)) {
					if ((includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type)) {
						result.add(beanName);
						// Match found for this bean: do not match FactoryBean itself anymore.
						continue;
					}
					// In case of FactoryBean, try to match FactoryBean itself next.
					beanName = FACTORY_BEAN_PREFIX + beanName;
				}
				// Match raw bean instance (might be raw FactoryBean).
				if (isTypeMatch(beanName, type)) {
					result.add(beanName);
				}
			}
			
		}

前一段的超长的逻辑判断看得人头疼,但是先看下半段的遍历,突然就找到了最关键判断类型匹配的函数 isTypeMatch,从名字就看出来,这应该就是判断类型匹配的地方啦。

然而点进去一看,居然是长达 100 行的函数。

# isTypeMatch

首先从单例中查找,匹配这个单例 bean 的类型和我们目标的类型,其中对 factoryBean 的处理也比较简单,就不再贴代码了。对于注册的 null instance ,也返回 false。

再从父工厂找,递归 isTypeMatch 。

再就是复杂的查找了。

先定义个 typesToMatch ,包括了目标类型和 FactoryBean .

然后我们再继续看代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Check decorated bean definition, if any: We assume it'll be easier
// to determine the decorated bean's type than the proxy's type.
// 先检查 bean 的装饰definition。
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
   RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
   Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
   if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
      return typeToMatch.isAssignableFrom(targetClass);
   }
}
// 注意此处predictBeanType返回了很关键的Class ,我们后面再详细分析此方法。
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
if (beanType == null) {
   return false;
}

// Check bean class whether we're dealing with a FactoryBean.
//接下来就是处理 FactoryBean
if (FactoryBean.class.isAssignableFrom(beanType)) {
   if (!BeanFactoryUtils.isFactoryDereference(name)) {
      // If it's a FactoryBean, we want to look at what it creates, not the factory class.
      beanType = getTypeForFactoryBean(beanName, mbd);
      if (beanType == null) {
         return false;
      }
   }
}
else if (BeanFactoryUtils.isFactoryDereference(name)) {
   // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
   // type but we nevertheless are being asked to dereference a FactoryBean...
   // Let's check the original bean class and proceed with it if it is a FactoryBean.
   beanType = predictBeanType(beanName, mbd, FactoryBean.class);
   if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
      return false;
   }
}
//对其 resolvableType 进行处理
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
   resolvableType = mbd.factoryMethodReturnType;
}
if (resolvableType != null && resolvableType.resolve() == beanType) {
   return typeToMatch.isAssignableFrom(resolvableType);
}
//如果以上都没有处理掉的话, 则判读typeToMatch和 beanType 
return typeToMatch.isAssignableFrom(beanType);

总结:

目前很遗憾 isTypeMatch 往下还有很复杂的逻辑暂时不能看懂,但是从外层的逻辑大致知道寻找所有匹配的beanName 的方法非常的“复杂粗暴”。遍历 beanDefinitionNames 已定义的所有 bean,即使是一个小型的项目也有近200个 bean 需要遍历,并且这数百个 beanName 还要遍历非常多次。

只能说根据 type 寻找 bean 实在是比根据 name 复杂了太多太多,从源码看真是深坑,理解了为什么作者直接忽略了这部分…应该是第二遍或第三遍阅读 Spring 源码时才能理解。