前言
spring容器獲取bean的方式主要有兩種,即byName和byType
byName方式相對簡單,即Object getBean(String name),通過beanName獲取,因為容器中存儲的就是一個beanName->bean實體的映射,如果沒有創(chuàng)建,則通過beanName查找bean定義,通過bean定義去創(chuàng)建即可
而byType,即T getBean(Class<T> requiredType),則復(fù)雜一點,因為不管是bean定義容器還是bean容器存儲形式都是以beanName為key的map,所以它的獲取方式肯定要多一步type->name的轉(zhuǎn)換
源碼
其實雖然容器的key是beanName,但想一下getByType并不難實現(xiàn),只要循環(huán)bean定義看看哪些bean的class是所查找的type,獲取到對應(yīng)的beanName,調(diào)用getByName就解決了
其實源碼也正是如此,跟一下源碼(以下代碼省略了一些支線邏輯)
getBeanByType
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBean(requiredType, (Object[]) null);
}
public <T> T getBean(Class<T> requiredType, @Nullable Object... args) throws BeansException {
// 調(diào)用resolveBean
Object resolved = resolveBean(ResolvableType.forRawClass(requiredType), args, false);
return (T) resolved;
}
最終調(diào)用resolveBean方法
resolveBean
private <T> T resolveBean(ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) {
NamedBeanHolder<T> namedBean = resolveNamedBean(requiredType, args, nonUniqueAsNull);
if (namedBean != null) {
return namedBean.getBeanInstance();
}
// 省略
return null;
}
調(diào)用resolveNamedBean
resolveNamedBean
private <T> NamedBeanHolder<T> resolveNamedBean(
ResolvableType requiredType, @Nullable Object[] args, boolean nonUniqueAsNull) throws BeansException {
// 調(diào)用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如果只有一個就達(dá)成目標(biāo)返回,多個就按自己的規(guī)矩選一個,最終通過getBeanByName實際獲取bean
getBeanNamesForType
getBeanNamesForType最終會走向doGetBeanNamesForType,這是spring源碼的一罐命名方式,不貼代碼了,直接看doGetBeanNamesForType
doGetBeanNamesForType
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
// 準(zhǔn)備好匹配的集合
List<String> result = new ArrayList<>();
// 循環(huán)所有bean定義名集合
for (String beanName : this.beanDefinitionNames) {
// 省略一些別名判斷,bean定義完整判斷,異常處理...
// 通過名字獲取beand定義
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 判斷是不是FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 是否匹配標(biāo)識
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);
}
}
// 省略查找手動注冊單例邏輯...
// 返回匹配集合結(jié)果
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是否匹配邏輯...
// 根據(jù)beanName獲取bean定義
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 要匹配的class
Class<?> classToMatch = typeToMatch.resolve();
// 省略FactoryBean相關(guān)邏輯
// bean的type
ResolvableType beanType = null;
if (beanType == null) {
// 獲取bean定義的targetType
ResolvableType definedType = mbd.targetType;
beanType = definedType;
}
// 判斷beanType是否可以轉(zhuǎn)換為要匹配的type
if (beanType != null) {
return typeToMatch.isAssignableFrom(beanType);
}
}
實際上就是查找bean定義的targetType屬性,看是否是所需type/子類/實現(xiàn),如果是就匹配上了
整個過程梳理下來:
getByType就是循環(huán)bean定義,查找bean定義的targetType屬性等于該type的對應(yīng)beanName,再調(diào)用getByName,就完成了通過類型查找bean

FactoryBean的特殊性
上面的代碼為了清晰省略了很多分支邏輯,其中FactoryBean的判斷是比較重要的一環(huán),所以還不能忽略
FactoryBean的特殊性在于,他實際是兩個對象,一個工廠對象(FactoryType),一個生產(chǎn)的對象(ObjectType,也是一般情況我們實際需要的對象),不熟悉FactoryBean可以看這里Spring FactoryBean源碼解析
問題的癥結(jié)在于FactoryBean的bean定義的targetType屬性是FactoryType,而我們一般需要注入的是FactoryBean.getObject生產(chǎn)的ObjectType
比如現(xiàn)在有個BookFactoryBean生產(chǎn)的是Book實體bean,當(dāng)我們getByType(Book.class)時,bean定義中并不存在targetType==Book.class的bean定義,只有targetType==BookFactoryBean.class的bean定義,按照上面的邏輯是無法根據(jù)type獲取到Book的beanName的

所以再回到doGetBeanNamesForType方法找回省略的FactoryBean邏輯,看spring如何解決這個問題
doGetBeanNamesForType
private String[] doGetBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) {
// 準(zhǔn)備好匹配的集合
List<String> result = new ArrayList<>();
// 循環(huán)所有bean定義名集合
for (String beanName : this.beanDefinitionNames) {
// 省略一些別名判斷,bean定義完整判斷,異常處理...
// 通過名字獲取beand定義
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 判斷是不是FactoryBean
boolean isFactoryBean = isFactoryBean(beanName, mbd);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 是否匹配標(biāo)識
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生產(chǎn)的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邏輯...
// 返回匹配集合結(jié)果
return StringUtils.toStringArray(result);
}
可以看到,如果是FactoryBean,最終依然使用isTypeMatch進(jìn)行判斷,所以重點還是在這個方法
后面還有一句如果不匹配則beanName = FACTORY_BEAN_PREFIX + beanName,并再次isTypeMatch判斷,其中FACTORY_BEAN_PREFIX = "&",熟悉FactoryBean的同學(xué)應(yīng)該知道這是查找FactoryBean本身,因為某些特殊情況,可能我們想注入的就是這個FactoryBean本身而不是他生產(chǎn)的bean
重點依然是看isTypeMatch是怎么處理FactoryBean的匹配問題的
isTypeMatch
/**
** 根據(jù)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是否匹配邏輯...
// 根據(jù)beanName獲取bean定義
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
// 要匹配的class
Class<?> classToMatch = typeToMatch.resolve();
// 將要匹配的class和FactoryBean.class組成一個數(shù)組,因為匹配的可能有兩種,一種是targetType就是class,一種是targetType是FactoryBean(保留可能性)
if (classToMatch == null) {
classToMatch = FactoryBean.class;
}
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
// 嘗試預(yù)測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, 要查看它創(chuàng)建了什么類型的bean,而不是工廠本身的Type
if (FactoryBean.class.isAssignableFrom(predictedType)) {
if (beanInstance == null && !isFactoryDereference) {
// 獲取FactoryBean創(chuàng)建的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,直接判斷是否可轉(zhuǎn)換為typeToMatch
if (beanType != null) {
return typeToMatch.isAssignableFrom(beanType);
}
// 如果沒有有明確beanType,判斷predictedType是否可轉(zhuǎn)換為typeToMatch
return typeToMatch.isAssignableFrom(predictedType);
}
邏輯看起來挺復(fù)雜,其實最重要的是如果是FactoryBean,調(diào)用getTypeForFactoryBean獲取其創(chuàng)建的ObjectType,那么看看getTypeForFactoryBean是如何獲取FactoryBean所創(chuàng)建的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)獲取或創(chuàng)建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實際上就是調(diào)用FactoryBean.getObjectType方法
protected Class<?> getTypeForFactoryBean(FactoryBean<?> factoryBean) {
try {
return factoryBean.getObjectType();
}
catch (Throwable ex) {
}
}
getObjectType就是我們實現(xiàn)FactoryBean接口時需要實現(xiàn)的方法,例如如下
@Component
public class BookFactory implements FactoryBean<Book> {
@Override
public Book getObject() {
return new Book();
}
@Override
public Class<?> getObjectType() {
return Book.class;
}
}
總結(jié)
getBeanByType 就是循環(huán)bean定義查找targetType==type,如果是FactoryBean查找objectType==type的唯一beanName,再通過getBeanByName就獲取到了bean~