前言
使用Spring,@Autowired注解肯定再熟悉不過了,今天徹底探究一下@Autowired實現的源碼細節
實現
其實這個實現方式其實思路很簡單:
就是在bean容器中找到type==@Autowired修飾的類型的bean,然后通過反射給屬性賦值即可
道理很簡單,但還是看代碼證實一下,并關注一些實現細節
例子
寫一個簡單的例子,為方便后續說明
// B Service
@Service
public class BService {
}
// A Service 通過@Autowired依賴注入 B Service
@Service
public class AService {
@Autowired
private BService bService;
}
@Autowired實現步驟
spring內部的默認bean工廠實現為DefaultListableBeanFactory
,然而該BeanFactory并不支持@Autowired注解
實際上@Autowired注解的支持是依靠于ApplicationContext向DefaultListableBeanFactory注冊了Autowired后置處理器:AutowiredAnnotationBeanPostProcessor
在bean創建周期的populateBean(填充屬性)中會執行該后置處理器的postProcessProperties
方法來完成依賴注入
步驟如下
1.查找帶有@Autowired的屬性
findAutowiringMetadata
方法查找了當前類屬性中帶有@Autowired,@Value的屬性,包裝成InjectionMetadata
其中autowiredAnnotationTypes主要包含兩個注解
二.通過beanFactory的resolveDependency
方法獲取需要依賴Bean
InjectionMetadata.inject方法中,調用beanFactory的resolveDependency
方法
其中desc即查找的目標,包含了目標的類型
三.給屬性賦值
inject方法最終獲取到依賴的bean后,反射完成屬性賦值
到此,依賴注入的功能就實現了
深入resolveDependency
上面的步驟都很好理解,重點是第二步通過beanFactory的resolveDependency
查找依賴的bean,所以再次深入探究beanFactory是如何獲取到依賴的bean的
以上例debugger一下調用resolveDependency
時的參數
beanName為“AService”即被注入的bean, desc中存放BService的一些信息: BService的類型
所以resolveDependency實際上是根據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) {
// 從多個里按優先級選擇一個,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, 轉換為實體
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// 返回以來的bean實體
Object result = instanceCandidate;
return result;
}
其中重點是:
- findAutowireCandidates:根據type查找依賴注入候選者
- determineAutowireCandidate: 當出現多候選者,選擇一個(畢竟依賴注入只能注入一個對象)
findAutowireCandidates
根據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());
// 初始化返回結構
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容器中進一步篩選候選者
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 返回結果
return result;
}
通過代碼可以看出,依賴的候選者來源有兩個地方:
- bean容器(使用addCandidateEntry方法加入返回map)
- resolvableDependencies(直接加入返回map)
其中bean容器的查找,交給方法BeanFactoryUtils.beanNamesForTypeIncludingAncestors
,那么resolvableDependencies是一個什么東西?
通過查看源碼,發現resolvableDependencies也是一個容器,存儲的是type->實體的map
再次查找發現容器內容添加基本只有一處,即registerResolvableDependency
registerResolvableDependency是一個public接口,實際上他的存在是為了實現依賴注入非Bean容器中的Bean,可以叫spring托管的外部bean
比如現在又個單例工具對象,你想讓其他bean可以依賴注入這個對象,同時又不想把這個對象加入bean容器,則可以使用registerResolvableDependency加入到resolvableDependencies(相當于給spring中加入一個創建好的對象,供其他bean依賴注入,但不需要spring去創建管理它)
再ApplicationContext初始化階段,會把ApplicationContext對象,BeanFactory對象通過registerResolvableDependency加入到spring中托管
這就是為什么我們的bean能依賴注入上下文對象和bean工廠本身,如下
當然resolvableDependencies依然只是支線邏輯,重點和大部分情況還是從bean容器中查找依賴,即BeanFactoryUtils.beanNamesForTypeIncludingAncestors方法,這個方法返回的是一個字符串數組,也就是beanName的數組,那怎么返回候選項Object的吶?
答案在addCandidateEntry
方法里,看一下它的內部
可以看見它往findAutowireCandidates的result里面的value塞了一個根據字符串getType獲取的type(Class)而不是bean的實體,這也是為什么上一步doResolveDependency
會有這么一步代碼
// 如果返回的是class, 轉換為實體
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
所以findAutowireCandidates返回的map可能是beanName->bean實體,但大部分情況下是beanName->beanClass
所以重點又回到了descriptor.resolveCandidate
方法,當通過BeanFactoryUtils獲取候選注入bean時,返回的是一個beanName->beanClass時,spring調用descriptor.resolveCandidate
方法通過beanName獲取實際注入的實體(此時beanClass基本就沒啥用了),而resolveCandidate方法內部也很簡單,既然有了beanName,直接根據beanName獲取bean即可:
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException {
return beanFactory.getBean(beanName);
}
getBeanByName就不展開了,這個是最基礎的,即通過beanName獲取bean定義,初始化創建bean
beanNamesForTypeIncludingAncestors
先看下定義
public static String[] beanNamesForTypeIncludingAncestors(
ListableBeanFactory lbf, Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
根據命名:通過type查詢beanName數組,參數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)
內部調用的方法,即根據type在bean容器中獲取bean,很好理解,本文就不展開了~
總結
總結一下@Autowired的整個過程,畫個示意圖如下