前言
spring容器获取bean的方式主要有两种,即byName
和byType
byName方式相对简单,即Object getBean(String name)
,通过beanName获取,因为容器中存储的就是一个beanName->bean实体的映射,如果没有创建,则通过beanName查找bean定义,通过bean定义去创建即可
而byType,即T getBean(Class
,则复杂一点,因为不管是bean定义容器还是bean容器存储形式都是以beanName为key的map,所以它的获取方式肯定要多一步type->name的转换
源码
其实虽然容器的key是beanName,但想一下getByType并不难实现,只要循环bean定义看看哪些bean的class是所查找的type,获取到对应的beanName,调用getByName就解决了
其实源码也正是如此,跟一下源码(以下代码省略了一些支线逻辑)
getBeanByType
public T getBean(Class requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
public T getBean(Class requiredType, @Nullable Object... args) throws BeansException {
// 调用resolveBean
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
return (T) resolved;
}
最终调用resolveBean
方法
resolveBean
private T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
NamedBeanHolder namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
// 省略
return null;
}
调用resolveNamedBean
resolveNamedBean
private NamedBeanHolder resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
// 调用getBeanNamesForType查找候选beanNames
String[] candidateNames = getBeanNamesForType(requiredType);
// 只有一个候选者,直接返回这个beanName
if (candidateNames.length == 1) {
String beanName = candidateNames[0];
// 这里的getBean就是getBeanByName
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
}
else if (candidateNames.length > 1) {
// 省略,大体意思是多个后选择从中选一个
}
return null;
}
所以重点就来到了getBeanNamesForType
,字面意思传给它一个type能返回所有该type的beanName,获取到这些beanName如果只有一个就达成目标返回,多个就按自己的规矩选一个,最终通过getBeanByName
实际获取bean
getBeanNamesForType
getBeanNamesForType最终会走向doGetBeanNamesForType
,这是spring源码的一罐命名方式,不贴代码了,直接看doGetBeanNamesForType
doGetBeanNamesForType
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
// 准备好匹配的集合
List result = new ArrayList<>();
// 循环所有bean定义名集合
for (String beanName : this.beanDefinitionNames) {
// 省略一些别名判断,bean定义完整判断,异常处理...
// 通过名字获取beand定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 判断是不是FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 是否匹配标识
boolean matchFound = false;
// 是否允许FactoryBean初始化
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
// 如果不是FactoryBean
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
// 使用isTypeMatch判断bean是否匹配type
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
// 如果是FactoryBean
else {
// 省略FactoryBean特殊处理
}
// 如果匹配,加入到匹配集合中
if (matchFound) {
result.add(beanName);
}
}
// 省略查找手动注册单例逻辑...
// 返回匹配集合结果
return StringUtils.toStringArray(result);
}
先不管FactoryBean的特殊处理,看看普通的bean,最终是通过isTypeMatch
方法判断是否匹配
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// 省略判断手动注册bean是否匹配逻辑...
// 根据beanName获取bean定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 要匹配的class
Class> classToMatch = typeToMatch.resolve();
// 省略FactoryBean相关逻辑
// bean的type
ResolvableType beanType = null;
if (beanType == null) {
// 获取bean定义的targetType
ResolvableType definedType = mbd.targetType;
beanType = definedType;
}
// 判断beanType是否可以转换为要匹配的type
if (beanType != null) {
return typeToMatch.isAssignableFrom(beanType);
}
}
实际上就是查找bean定义的targetType
属性,看是否是所需type/子类/实现,如果是就匹配上了
整个过程梳理下来:
getByType就是循环bean定义,查找bean定义的targetType
属性等于该type的对应beanName,再调用getByName,就完成了通过类型查找bean
FactoryBean的特殊性
上面的代码为了清晰省略了很多分支逻辑,其中FactoryBean的判断是比较重要的一环,所以还不能忽略
FactoryBean的特殊性在于,他实际是两个对象,一个工厂对象(FactoryType),一个生产的对象(ObjectType,也是一般情况我们实际需要的对象),不熟悉FactoryBean可以看这里Spring FactoryBean源码解析
问题的症结在于FactoryBean的bean定义的targetType属性是FactoryType,而我们一般需要注入的是FactoryBean.getObject生产的ObjectType
比如现在有个BookFactoryBean
生产的是Book
实体bean,当我们getByType(Book.class)时,bean定义中并不存在targetType==Book.class
的bean定义,只有targetType==BookFactoryBean.class
的bean定义,按照上面的逻辑是无法根据type获取到Book的beanName的
所以再回到doGetBeanNamesForType
方法找回省略的FactoryBean逻辑,看spring如何解决这个问题
doGetBeanNamesForType
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
// 准备好匹配的集合
List result = new ArrayList<>();
// 循环所有bean定义名集合
for (String beanName : this.beanDefinitionNames) {
// 省略一些别名判断,bean定义完整判断,异常处理...
// 通过名字获取beand定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 判断是不是FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 是否匹配标识
boolean matchFound = false;
// 是否允许FactoryBean初始化
boolean allowFactoryBeanInit = (allowEagerInit || containsSingleton(beanName));
boolean isNonLazyDecorated = (dbd != null && !mbd.isLazyInit());
// 如果不是FactoryBean
if (!isFactoryBean) {
if (includeNonSingletons || isSingleton(beanName, mbd, dbd)) {
// 使用isTypeMatch判断bean是否匹配type
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
// 如果是FactoryBean
else {
if (includeNonSingletons || isNonLazyDecorated ||
(allowFactoryBeanInit && isSingleton(beanName, mbd, dbd))) {
// 使用isTypeMatch判断FactoryBean生产的bean是否匹配type
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
// 如果查不到
if (!matchFound) {
// 判断FactoryBean本身是否匹配type
beanName = FACTORY_BEAN_PREFIX + beanName;
matchFound = isTypeMatch(beanName, type, allowFactoryBeanInit);
}
}
// 如果匹配,加入到匹配集合中
if (matchFound) {
result.add(beanName);
}
}
// 省略查找手动注册bean逻辑...
// 返回匹配集合结果
return StringUtils.toStringArray(result);
}
可以看到,如果是FactoryBean,最终依然使用isTypeMatch
进行判断,所以重点还是在这个方法
后面还有一句如果不匹配则beanName = FACTORY_BEAN_PREFIX + beanName
,并再次isTypeMatch判断,其中FACTORY_BEAN_PREFIX = "&"
,熟悉FactoryBean的同学应该知道这是查找FactoryBean本身,因为某些特殊情况,可能我们想注入的就是这个FactoryBean本身而不是他生产的bean
重点依然是看isTypeMatch
是怎么处理FactoryBean的匹配问题的
isTypeMatch
/**
** 根据beanName判断与typeToMatch是否匹配
*/
protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit)
throws NoSuchBeanDefinitionException {
String beanName = transformedBeanName(name);
// beanName是不是FactoryBean本身的name,即以&开头
boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name);
// 省略判断手动注册bean是否匹配逻辑...
// 根据beanName获取bean定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 要匹配的class
Class> classToMatch = typeToMatch.resolve();
// 将要匹配的class和FactoryBean.class组成一个数组,因为匹配的可能有两种,一种是targetType就是class,一种是targetType是FactoryBean(保留可能性)
if (classToMatch == null) {
classToMatch = FactoryBean.class;
}
Class>[] typesToMatch = (FactoryBean.class == classToMatch ?
new Class>[] {classToMatch} : new Class>[] {FactoryBean.class, classToMatch});
// 尝试预测bean的Type
Class> predictedType = null;
// 省略修饰bean定义逻辑
// predictBeanType(beanName, mbd, typesToMatch)就是获取bean定义的targetType
if (predictedType == null) {
predictedType = predictBeanType(beanName, mbd, typesToMatch);
if (predictedType == null) {
return false;
}
}
// 尝试获取bean的实际Type
ResolvableType beanType = null;
// 如果是FactoryBean, 要查看它创建了什么类型的bean,而不是工厂本身的Type
if (FactoryBean.class.isAssignableFrom(predictedType)) {
if (beanInstance == null && !isFactoryDereference) {
// 获取FactoryBean创建的type
beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit);
predictedType = beanType.resolve();
if (predictedType == null) {
return false;
}
}
}
else if (isFactoryDereference) {
// 如果是FactoryBean本身,还是直接查bean定义的targetType
predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) {
return false;
}
}
// 如果没有明确的beanType,但mdb的targetType或factoryMethodReturnType等于predictedType,则可以使用它们作为明确的beanType
if (beanType == null) {
ResolvableType definedType = mbd.targetType;
if (definedType == null) {
definedType = mbd.factoryMethodReturnType;
}
if (definedType != null && definedType.resolve() == predictedType) {
beanType = definedType;
}
}
// 如果有明确beanType,直接判断是否可转换为typeToMatch
if (beanType != null) {
return typeToMatch.isAssignableFrom(beanType);
}
// 如果没有有明确beanType,判断predictedType是否可转换为typeToMatch
return typeToMatch.isAssignableFrom(predictedType);
}
逻辑看起来挺复杂,其实最重要的是如果是FactoryBean,调用getTypeForFactoryBean
获取其创建的ObjectType,那么看看getTypeForFactoryBean是如何获取FactoryBean所创建的ObjectType
getTypeForFactoryBean
protected ResolvableType getTypeForFactoryBean(String beanName, RootBeanDefinition mbd, boolean allowInit) {
// bean定义指明的ObjectType
ResolvableType result = getTypeForFactoryBeanFromAttributes(mbd);
// 取到就返回
if (result != ResolvableType.NONE) {
return result;
}
// 上面没取到,则通过doGetBean(FACTORY_BEAN_PREFIX + beanName)获取或创建FactoryBean工厂本身的对象
if (allowInit && mbd.isSingleton()) {
try {
FactoryBean> factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true);
// 通过getTypeForFactoryBean方法获取ObjectType
Class> objectType = getTypeForFactoryBean(factoryBean);
return (objectType != null) ? ResolvableType.forClass(objectType) : ResolvableType.NONE;
}
catch (BeanCreationException ex) {
// 省略异常处理
}
}
return ResolvableType.NONE;
}
上面的代码分两步,如果bean定义包含了返回的objectType,则直接返回,否则去bean容器查找FactoryBean的实例,通过getTypeForFactoryBean
获取FactoryBean的ObjectType,这里getTypeForFactoryBean实际上就是调用FactoryBean.getObjectType
方法
protected Class> getTypeForFactoryBean(FactoryBean> factoryBean) {
try {
return factoryBean.getObjectType();
}
catch (Throwable ex) {
}
}
getObjectType
就是我们实现FactoryBean接口时需要实现的方法,例如如下
@Component
public class BookFactory implements FactoryBean {
@Override
public Book getObject() {
return new Book();
}
@Override
public Class> getObjectType() {
return Book.class;
}
}
总结
getBeanByType 就是循环bean定义查找targetType==type
,如果是FactoryBean查找objectType==type
的唯一beanName,再通过getBeanByName就获取到了bean~