前言
使用Spring,@Autowired注解肯定再熟悉不過了峭拘,今天徹底探究一下@Autowired實現(xiàn)的源碼細(xì)節(jié)
實現(xiàn)
其實這個實現(xiàn)方式其實思路很簡單:
就是在bean容器中找到type==@Autowired修飾的類型的bean姚糊,然后通過反射給屬性賦值即可
道理很簡單,但還是看代碼證實一下,并關(guān)注一些實現(xiàn)細(xì)節(jié)
例子
寫一個簡單的例子踪栋,為方便后續(xù)說明
// B Service
@Service
public class BService {
}
// A Service 通過@Autowired依賴注入 B Service
@Service
public class AService {
@Autowired
private BService bService;
}
@Autowired實現(xiàn)步驟
spring內(nèi)部的默認(rèn)bean工廠實現(xiàn)為DefaultListableBeanFactory
敛腌,然而該BeanFactory并不支持@Autowired注解
實際上@Autowired注解的支持是依靠于ApplicationContext向DefaultListableBeanFactory注冊了Autowired后置處理器:AutowiredAnnotationBeanPostProcessor
在bean創(chuàng)建周期的populateBean(填充屬性)中會執(zhí)行該后置處理器的postProcessProperties
方法來完成依賴注入
步驟如下
1.查找?guī)в蠤Autowired的屬性
findAutowiringMetadata
方法查找了當(dāng)前類屬性中帶有@Autowired卧土,@Value的屬性,包裝成InjectionMetadata
其中autowiredAnnotationTypes主要包含兩個注解
二.通過beanFactory的resolveDependency
方法獲取需要依賴Bean
InjectionMetadata.inject方法中像樊,調(diào)用beanFactory的resolveDependency
方法
其中desc即查找的目標(biāo)尤莺,包含了目標(biāo)的類型
三.給屬性賦值
inject方法最終獲取到依賴的bean后,反射完成屬性賦值
到此生棍,依賴注入的功能就實現(xiàn)了
深入resolveDependency
上面的步驟都很好理解颤霎,重點是第二步通過beanFactory的resolveDependency
查找依賴的bean,所以再次深入探究beanFactory是如何獲取到依賴的bean的
以上例debugger一下調(diào)用resolveDependency
時的參數(shù)
beanName為“AService”即被注入的bean, desc中存放BService的一些信息: BService的類型
所以resolveDependency實際上是根據(jù)type獲取bean,即getBeanByType
友酱,再深入看一下(以下代碼都是省略了分支邏輯和緩存邏輯晴音,只保留重點邏輯)
resolveDependency:
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
// spring一般doXXX就是實際的主干代碼,如createBean和doCreateBean
Object result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
return result;
}
再來doResolveDependency:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 獲取依賴的type粹污,使用type去bean容器查找
Class<?> type = descriptor.getDependencyType();
// 查找所有符合的bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 依賴的beanName
String autowiredBeanName;
// 依賴的bean實體
Object instanceCandidate;
// 一般情況只有一個段多,但多個符合的也要處理
if (matchingBeans.size() > 1) {
// 從多個里按優(yōu)先級選擇一個,determine即下決定
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 只有一個的情況(大部分情況)壮吩,直接取第一個
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
// 如果返回的是class, 轉(zhuǎn)換為實體
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// 返回以來的bean實體
Object result = instanceCandidate;
return result;
}
其中重點是:
- findAutowireCandidates:根據(jù)type查找依賴注入候選者
- determineAutowireCandidate: 當(dāng)出現(xiàn)多候選者进苍,選擇一個(畢竟依賴注入只能注入一個對象)
findAutowireCandidates
根據(jù)type查找依賴注入候選者,先看一下它的定義
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
其中:
- beanName:將被填充屬性的bean的name
- requiredType:填充的類型鸭叙,即要查找的依賴
- DependencyDescriptor:依賴的一些描述
- 返回一個Map<String, Object>觉啊,即beanName和bean實體的映射map(value不一定都是bean實體,有可能是實體的類)沈贝,一般情況下返回的map.size==1杠人,但也會有多個的情況
再來看下具體代碼
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 使用BeanFactoryUtils篩選Bean容器中的候選者
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
// 初始化返回結(jié)構(gòu)
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 1.從resolvableDependencies中篩選候選者
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 2.從bean容器中進(jìn)一步篩選候選者
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 返回結(jié)果
return result;
}
通過代碼可以看出,依賴的候選者來源有兩個地方:
- bean容器(使用addCandidateEntry方法加入返回map)
- resolvableDependencies(直接加入返回map)
其中bean容器的查找宋下,交給方法BeanFactoryUtils.beanNamesForTypeIncludingAncestors
嗡善,那么resolvableDependencies是一個什么東西?
通過查看源碼学歧,發(fā)現(xiàn)resolvableDependencies也是一個容器罩引,存儲的是type->實體的map
再次查找發(fā)現(xiàn)容器內(nèi)容添加基本只有一處,即registerResolvableDependency
registerResolvableDependency是一個public接口枝笨,實際上他的存在是為了實現(xiàn)依賴注入非Bean容器中的Bean袁铐,可以叫spring托管的外部bean
比如現(xiàn)在又個單例工具對象,你想讓其他bean可以依賴注入這個對象横浑,同時又不想把這個對象加入bean容器剔桨,則可以使用registerResolvableDependency加入到resolvableDependencies(相當(dāng)于給spring中加入一個創(chuàng)建好的對象,供其他bean依賴注入徙融,但不需要spring去創(chuàng)建管理它)
再ApplicationContext初始化階段洒缀,會把ApplicationContext對象,BeanFactory對象通過registerResolvableDependency加入到spring中托管
這就是為什么我們的bean能依賴注入上下文對象和bean工廠本身欺冀,如下
當(dāng)然resolvableDependencies依然只是支線邏輯树绩,重點和大部分情況還是從bean容器中查找依賴,即BeanFactoryUtils.beanNamesForTypeIncludingAncestors方法脚猾,這個方法返回的是一個字符串?dāng)?shù)組葱峡,也就是beanName的數(shù)組砚哗,那怎么返回候選項Object的吶龙助?
答案在addCandidateEntry
方法里,看一下它的內(nèi)部
可以看見它往findAutowireCandidates的result里面的value塞了一個根據(jù)字符串getType獲取的type(Class)而不是bean的實體,這也是為什么上一步doResolveDependency
會有這么一步代碼
// 如果返回的是class, 轉(zhuǎn)換為實體
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
所以findAutowireCandidates返回的map可能是beanName->bean實體提鸟,但大部分情況下是beanName->beanClass
所以重點又回到了descriptor.resolveCandidate
方法军援,當(dāng)通過BeanFactoryUtils獲取候選注入bean時,返回的是一個beanName->beanClass時称勋,spring調(diào)用descriptor.resolveCandidate
方法通過beanName獲取實際注入的實體(此時beanClass基本就沒啥用了)胸哥,而resolveCandidate方法內(nèi)部也很簡單,既然有了beanName赡鲜,直接根據(jù)beanName獲取bean即可:
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException {
return beanFactory.getBean(beanName);
}
getBeanByName就不展開了空厌,這個是最基礎(chǔ)的,即通過beanName獲取bean定義银酬,初始化創(chuàng)建bean
beanNamesForTypeIncludingAncestors
先看下定義
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
根據(jù)命名:通過type查詢beanName數(shù)組,參數(shù)type即查找的類型,IncludingAncestors
代表如果lbf有父級贪磺,要遞歸去祖先bean工廠中查找拧略,看下代碼
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
Assert.notNull(lbf, "ListableBeanFactory must not be null");
// 使用beanFactory的getBeanNamesForType方法查找
String[] result = lbf.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
// 如果有父級,遞歸查找
if (lbf instanceof HierarchicalBeanFactory) {
HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf;
if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) {
String[] parentResult = beanNamesForTypeIncludingAncestors(
(ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit);
result = mergeNamesWithParent(result, parentResult, hbf);
}
}
return result;
}
所以其實最核心的方法就是BeanFactory.getBeanNamesForType
李破,也就是常用的方法getBean(Class<T> requiredType)
內(nèi)部調(diào)用的方法宠哄,即根據(jù)type在bean容器中獲取bean,很好理解嗤攻,本文就不展開了~
總結(jié)
總結(jié)一下@Autowired的整個過程毛嫉,畫個示意圖如下