本系列文章:
java配置類爲何要添加@Configuration註解?
spring談談Spring中的對象跟Bean,你知道Spring怎麼建立對象的嗎?
數組推薦閱讀:
緩存Spring雜談
app本系列文章將會帶你一行行的將Spring的源碼吃透,推薦閱讀的文章是閱讀源碼的基礎!編輯器
」
前言
在前面的文章中已經知道了Spring是如何將一個對象建立出來的,那麼緊接着,Spring就須要將這個對象變成一個真正的Bean了,這個過程主要分爲兩步ide
-
屬性注入 -
初始化
在這兩個過程當中,Bean的後置處理器會穿插執行,其中有些後置處理器是爲了幫助完成屬性注入或者初始化的,而有些後置處理器是Spring提供給程序員進行擴展的,固然,這兩者並不衝突。整個Spring建立對象並將對象變成Bean的過程就是咱們常常提到了Spring中Bean的生命週期。固然,本系列源碼分析的文章不會再對生命週期的概念作過多闡述了,若是你們有這方面的需求的話能夠參考我以前的文章,或者關注個人公衆號:程序員DMZ
Spring官網閱讀(九)Spring中Bean的生命週期(上)
Spring官網閱讀(十)Spring中Bean的生命週期(下)
源碼分析
閒話再也不多說,咱們正式進入源碼分析階段,本文重點要分析的方法就是org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
,其源碼以下:
doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 建立對象的過程在上篇文章中咱們已經介紹過了,這裏再也不贅述
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 獲取到建立的這個對象
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
// 按照官方的註釋來講,這個地方是Spring提供的一個擴展點,對程序員而言,咱們能夠經過一個實現了MergedBeanDefinitionPostProcessor的後置處理器來修改bd中的屬性,從而影響到後續的Bean的生命週期
// 不過官方本身實現的後置處理器並無去修改bd,而是調用了applyMergedBeanDefinitionPostProcessors方法
// 這個方法名直譯過來就是-應用合併後的bd,也就是說它這裏只是對bd作了進一步的使用而沒有真正的修改
synchronized (mbd.postProcessingLock) {
// bd只容許被處理一次
if (!mbd.postProcessed) {
try {
// 應用合併後的bd
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
// 標註這個bd已經被MergedBeanDefinitionPostProcessor的後置處理器處理過
// 那麼在第二次建立Bean的時候,不會再次調用applyMergedBeanDefinitionPostProcessors
mbd.postProcessed = true;
}
}
// 這裏是用來出來循環依賴的,關於循環以來,在介紹完正常的Bean的建立後,單獨用一篇文章說明
// 這裏不作過多解釋
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 咱們這篇文章重點要分析的就是populateBean方法,在這個方法中完成了屬性注入
populateBean(beanName, mbd, instanceWrapper);
// 初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
// 省略異常代碼
}
// 後續代碼不在本文探討範圍內了,暫不考慮
return exposedObject;
}
applyMergedBeanDefinitionPostProcessors
源碼以下:
// 能夠看到這個方法的代碼仍是很簡單的,就是調用了MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
這個時候咱們就要思考一個問題,容器中如今有哪些後置處理器是MergedBeanDefinitionPostProcessor
呢?
![](http://static.javashuo.com/static/loading.gif)
查看這個方法的實現類咱們會發現總共就這麼幾個類實現了MergedBeanDefinitionPostProcessor
接口。實際上除了ApplicationListenerDetector
以外,其他的後置處理器的邏輯都差很少。咱們在這裏咱們主要就分析兩個後置處理
-
ApplicationListenerDetector -
AutowiredAnnotationBeanPostProcessor
ApplicationListenerDetector
首先,咱們來ApplicationListenerDetector
,這個類在以前的文章中也屢次提到過了,它的做用是用來處理嵌套Bean的狀況,主要是保證能將嵌套在Bean標籤中的ApplicationListener
也能添加到容器的監聽器集合中去。咱們先經過一個例子來感覺下這個後置處理器的做用吧
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.dmz.source.populate.service.DmzService" id="dmzService">
<constructor-arg name="orderService">
<bean class="com.dmz.source.populate.service.OrderService"/>
</constructor-arg>
</bean>
</beans>
示例代碼:
// 事件
public class DmzEvent extends ApplicationEvent {
public DmzEvent(Object source) {
super(source);
}
}
public class DmzService {
OrderService orderService;
public DmzService(OrderService orderService) {
this.orderService = orderService;
}
}
// 實現ApplicationListener接口
public class OrderService implements ApplicationListener<DmzEvent> {
@Override
public void onApplicationEvent(DmzEvent event) {
System.out.println(event.getSource());
}
}
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("application-populate.xml");
cc.publishEvent(new DmzEvent("my name is dmz"));
}
}
// 程序運行結果,控制檯打印:my name is dmz
說明OrderService
已經被添加到了容器的監聽器集合中。可是請注意,在這種狀況下,若是要使OrderService
可以執行監聽的邏輯,必需要知足下面這兩個條件
-
外部的Bean要是單例的,對於咱們的例子而言就是dmzService -
內嵌的Bean也必須是單例的,在上面的例子中也就是orderService必須是單例
另外須要注意的是,這種嵌套的Bean比較特殊,它雖然由Spring建立,可是確不存在於容器中,就是說咱們不能將其做爲依賴注入到別的Bean中。
AutowiredAnnotationBeanPostProcessor
對應源碼以下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
// 找到注入的元數據,第一次是構建,後續能夠直接從緩存中拿
// 註解元數據其實就是當前這個類中的全部須要進行注入的「點」的集合,
// 注入點(InjectedElement)包含兩種,字段/方法
// 對應的就是AutowiredFieldElement/AutowiredMethodElement
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
// 排除掉被外部管理的注入點
metadata.checkConfigMembers(beanDefinition);
}
上面代碼的核心邏輯就是
-
找到全部的注入點,其實就是被@Autowired註解修飾的方法以及字段,同時靜態的方法以及字段也會被排除 -
排除掉被外部管理的注入點,在後續的源碼分析中咱們再細說
findAutowiringMetadata
// 這個方法的核心邏輯就是先從緩存中獲取已經解析好的注入點信息,很明顯,在原型狀況下才會使用緩存
// 建立注入點的核心邏輯在buildAutowiringMetadata方法中
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
// 可能咱們會修改bd中的class屬性,那麼InjectionMetadata中的注入點信息也須要刷新
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
// 這裏真正建立注入點
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
buildAutowiringMetadata
// 咱們應用中使用@Autowired註解標註在字段上或者setter方法可以完成屬性注入
// 就是由於這個方法將@Autowired註解標註的方法以及字段封裝成InjectionMetadata
// 在後續階段會調用InjectionMetadata的inject方法進行注入
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 處理全部的被@AutoWired/@Value註解標註的字段
ReflectionUtils.doWithLocalFields(targetClass, field -> {
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
// 靜態字段會直接跳過
if (Modifier.isStatic(field.getModifiers())) {
// 省略日誌打印
return;
}
// 獲得@AutoWired註解中的required屬性
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 處理全部的被@AutoWired註解標註的方法,相對於字段而言,這裏須要對橋接方法進行特殊處理
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 只處理一種特殊的橋接場景,其他的橋接方法都會被忽略
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
// 處理方法時須要注意,當父類中的方法被子類重寫時,若是子父類中的方法都加了@Autowired
// 那麼此時父類方法不能被處理,即不能被封裝成一個AutowiredMethodElement
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
// 省略日誌打印
return;
}
if (method.getParameterCount() == 0) {
// 當方法的參數數量爲0時,雖然不須要進行注入,可是仍是會把這個方法做爲注入點使用
// 這個方法最終仍是會被調用
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
// PropertyDescriptor: 屬性描述符
// 就是經過解析getter/setter方法,例如void getA()會解析獲得一個屬性名稱爲a
// readMethod爲getA的PropertyDescriptor,
// 在《Spring官網閱讀(十四)Spring中的BeanWrapper及類型轉換》文中已經作過解釋
// 這裏再也不贅述,這裏之因此來這麼一次查找是由於當XML中對這個屬性進行了配置後,
// 那麼就不會進行自動注入了,XML中顯示指定的屬性優先級高於註解
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); // 構造一個對應的AutowiredMethodElement,後續這個方法會被執行
// 方法的參數會被自動注入,這裏不限於setter方法
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
// 會處理父類中字段上及方法上的@AutoWired註解,而且父類的優先級比子類高
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
難點代碼分析
上面的代碼總體來講應該很簡單,就如咱們以前所說的,處理帶有@Autowired註解的字段及方法,同時會過濾掉全部的靜態字段及方法。上面複雜的地方在於對橋接方法的處理,可能大部分人都沒辦法理解這幾行代碼:
// 第一行
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
// 第二行
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
// 第三行
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
}
要理解這些代碼,首先你得知道什麼是橋接,爲此我已經寫好了一篇文章:
除了在上面的文章中提到的橋接方法外,還有一種特殊的狀況
// A類跟B類在同一個包下,A不是public的
class A {
public void test(){
}
}
// 在B中會生成一個跟A中的方法描述符(參數+返回值)如出一轍的橋接方法
// 這個橋接方法實際上就是調用父類中的方法
// 具體能夠參考:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=63424113
public class B extends A {
}
在理解了什麼是橋接以後,那麼上邊的第一行
代碼你應該就能看懂了,就以上面的代碼爲例,B中會生成一個橋接方法,對應的被橋接的方法就是A中的test
方法。
接着,咱們看看第二行代碼
public static boolean isVisibilityBridgeMethodPair(Method bridgeMethod, Method bridgedMethod) {
// 說明這個方法自己就不是橋接方法,直接返回true
if (bridgeMethod == bridgedMethod) {
return true;
}
// 說明是橋接方法,而且方法描述符一致
// 當且僅當是上面例子中描述的這種橋接的時候這個判斷纔會知足
// 正常來講橋接方法跟被橋接方法的返回值+參數類型確定不一致
// 因此這個判斷會過濾掉其他的全部類型的橋接方法
// 只會保留本文說起這種特殊狀況下產生的橋接方法
return (bridgeMethod.getReturnType().equals(bridgedMethod.getReturnType()) &&
Arrays.equals(bridgeMethod.getParameterTypes(), bridgedMethod.getParameterTypes()));
}
最後,再來看看第三行
代碼,核心就是這句method.equals(ClassUtils.getMostSpecificMethod(method, clazz)
。這句代碼的主要目的就是爲了處理下面這種狀況
@Component
public class D extends C {
@Autowired
@Override
public void setDmzService(DmzService dmzService) {
dmzService.init();
this.dmzService = dmzService;
}
}
// C不是Spring中的組件
public class C {
DmzService dmzService;
@Autowired
public void setDmzService(DmzService dmzService) {
this.dmzService = dmzService;
}
}
這種狀況下,在處理D中的@Autowired註解時,雖然咱們要處理父類中的@Autowired
註解,可是由於子類中的方法已經複寫了父類中的方法,因此此時應該要跳過父類中的這個被複寫的方法,這就是第三行
代碼的做用。
小結
到這裏咱們主要分析了applyMergedBeanDefinitionPostProcessors
這段代碼的做用,它的執行時機是在建立對象以後,屬性注入以前。按照官方的定義來講,到這裏咱們仍然可使用這個方法來修改bd的定義,那麼相對於經過BeanFactoryPostProcessor
的方式修改bd,applyMergedBeanDefinitionPostProcessors
這個方法影響的範圍更小,BeanFactoryPostProcessor
影響的是整個Bean的生命週期,而applyMergedBeanDefinitionPostProcessors
只會影響屬性注入以後的生命週期。
其次,咱們分析了Spring中內置的MergedBeanDefinitionPostProcessor
,選取了其中兩個特殊的後置處理器進行分析,其中ApplicationListenerDetector
主要處理內嵌的事件監聽器,而AutowiredAnnotationBeanPostProcessor
主要用於處理@Autowired註解,實際上咱們會發現,到這裏還只是完成了@Autowired註解的解析,尚未真正開始進行注入,真正注入的邏輯在後面咱們要分析的populateBean
方法中,在這個方法中會使用解析好的注入元信息完成真正的屬性注入,那麼接下來咱們就開始分析populateBean
這個方法的源碼。
populateBean
循環依賴的代碼咱們暫且跳過,後續出一篇專門文章解讀循環依賴,咱們直接看看populateBean到底作了什麼。
」
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 處理空實例
if (bw == null) {
// 若是建立的對象爲空,可是在XML中又配置了須要注入的屬性的話,那麼直接報錯
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// 空對象,不進行屬性注入
return;
}
}
// 知足兩個條件,不是合成類 && 存在InstantiationAwareBeanPostProcessor
// 其中InstantiationAwareBeanPostProcessor主要做用就是做爲Bean的實例化先後的鉤子
// 外加完成屬性注入,對於三個方法就是
// postProcessBeforeInstantiation 建立對象前調用
// postProcessAfterInstantiation 對象建立完成,@AutoWired註解解析後調用
// postProcessPropertyValues(已過時,被postProcessProperties替代) 進行屬性注入
// 下面這段代碼的主要做用就是咱們能夠提供一個InstantiationAwareBeanPostProcessor
// 提供的這個後置處理若是實現了postProcessAfterInstantiation方法而且返回false
// 那麼能夠跳過Spring默認的屬性注入,可是這也意味着咱們要本身去實現屬性注入的邏輯
// 因此通常狀況下,咱們也不會這麼去擴展
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
// 這裏其實就是判斷XML是否提供了屬性相關配置
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 確認注入模型
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 主要處理byName跟byType兩種注入模型,byConstructor這種注入模型在建立對象的時候已經處理過了
// 這裏都是對自動注入進行處理,byName跟byType兩種注入模型均是依賴setter方法
// byName,根據setter方法的名字來查找對應的依賴,例如setA,那麼就是去容器中查找名字爲a的Bean
// byType,根據setter方法的參數類型來查找對應的依賴,例如setXx(A a),就是去容器中查詢類型爲A的bean
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
// pvs是XML定義的屬性
// 自動注入後,bean實際用到的屬性就應該要替換成自動注入後的屬性
pvs = newPvs;
}
// 檢查是否有InstantiationAwareBeanPostProcessor
// 前面說過了,這個後置處理器就是來完成屬性注入的
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 是否須要依賴檢查,默認是不會進行依賴檢查的
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
// 下面這段代碼有點麻煩了,由於涉及到版本問題
// 其核心代碼就是調用了postProcessProperties完成了屬性注入
PropertyDescriptor[] filteredPds = null;
// 存在InstantiationAwareBeanPostProcessor,咱們須要調用這類後置處理器的方法進行注入
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 這句就是核心
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
// 獲得須要進行依賴檢查的屬性的集合
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 這個方法已通過時了,放到這裏就是爲了兼容老版本
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
// 須要進行依賴檢查
if (needsDepCheck) {
if (filteredPds == null) {
// 獲得須要進行依賴檢查的屬性的集合
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 對須要進行依賴檢查的屬性進行依賴檢查
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 將XML中的配置屬性應用到Bean上
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
上面這段代碼主要能夠拆分爲三個部分
-
處理自動注入 -
處理屬性注入(主要指處理@Autowired註解),最重要 -
處理依賴檢查
處理自動注入
autowireByName
對應源碼以下:
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 獲得符合下面條件的屬性名稱
// 1.有setter方法
// 2.須要進行依賴檢查
// 3.不包含在XML配置中
// 4.不是簡單類型(基本數據類型,枚舉,日期等)
// 這裏能夠看到XML配置優先級高於自動注入的優先級
// 不進行依賴檢查的屬性,也不會進行屬性注入
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
// 將自動注入的屬性添加到pvs中去
pvs.add(propertyName, bean);
// 註冊bean之間的依賴關係
registerDependentBean(propertyName, beanName);
// 忽略日誌
}
// 忽略日誌
}
}
看到了嗎?代碼就是這麼的簡單,不是要經過名稱注入嗎?直接經過beanName調用getBean,完事兒
autowireByType
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 這個類型轉換器,主要是在處理@Value時須要使用
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 獲得符合下面條件的屬性名稱
// 1.有setter方法
// 2.須要進行依賴檢查
// 3.不包含在XML配置中
// 4.不是簡單類型(基本數據類型,枚舉,日期等)
// 這裏能夠看到XML配置優先級高於自動注入的優先級
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
if (Object.class != pd.getPropertyType()) {
// 這裏獲取到的就是setter方法的參數,由於咱們須要按照類型進行注入嘛
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// 若是是PriorityOrdered在進行類型匹配時不會去匹配factoryBean
// 若是不是PriorityOrdered,那麼在查找對應類型的依賴的時候會會去匹factoryBean
// 這就是Spring的一種設計理念,實現了PriorityOrdered接口的Bean被認爲是一種
// 最高優先級的Bean,這一類的Bean在進行爲了完成裝配而去檢查類型時,
// 不去檢查factoryBean
// 具體能夠參考PriorityOrdered接口上的註釋文檔
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
// 將參數封裝成爲一個依賴描述符
// 依賴描述符會經過:依賴所在的類,字段名/方法名,依賴的具體類型等來描述這個依賴
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析依賴,這裏會處理@Value註解
// 另外,經過指定的類型到容器中查找對應的bean
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 將查找出來的依賴屬性添加到pvs中,後面會將這個pvs應用到bean上
pvs.add(propertyName, autowiredArgument);
}
// 註冊bean直接的依賴關係
for (String autowiredBeanName : autowiredBeanNames) {
registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
resolveDependency
這個方法在Spring雜談 | 什麼是ObjectFactory?什麼是ObjectProvider?已經作過度析了,本文再也不贅述。
能夠看到,真正作事的方法是
」doResolveDependency
@Override
public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName, Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// descriptor表明當前須要注入的那個字段,或者方法的參數,也就是注入點
// ParameterNameDiscovery用於解析方法參數名稱
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 1. Optional<T>
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
// 2. ObjectFactory<T>、ObjectProvider<T>
} else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
// 3. javax.inject.Provider<T>
} else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
} else {
// 4. @Lazy
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
// 5. 正常狀況
if (result == null) {
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 {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 依賴的具體類型
Class<?> type = descriptor.getDependencyType();
// 處理@Value註解,這裏獲得的時候@Value中的值
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
if (value instanceof String) {
// 解析@Value中的佔位符
String strVal = resolveEmbeddedValue((String) value);
// 獲取到對應的bd
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
// 處理EL表達式
value = evaluateBeanDefinitionString(strVal, bd);
}
// 經過解析el表達式可能還須要進行類型轉換
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
// 對map,collection,數組類型的依賴進行處理
// 最終會根據集合中的元素類型,調用findAutowireCandidates方法
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 根據指定類型可能會找到多個bean
// 這裏返回的既有多是對象,也有多是對象的類型
// 這是由於到這裏還不能明確的肯定當前bean到底依賴的是哪個bean
// 因此若是隻會返回這個依賴的類型以及對應名稱,最後還須要調用getBean(beanName)
// 去建立這個Bean
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
// 一個都沒找到,直接拋出異常
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 經過類型找到了多個
if (matchingBeans.size() > 1) {
// 根據是不是主Bean
// 是不是最高優先級的Bean
// 是不是名稱匹配的Bean
// 來肯定具體的須要注入的Bean的名稱
// 到這裏能夠知道,Spring在查找依賴的時候遵循先類型再名稱的原則(沒有@Qualifier註解狀況下)
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
// 沒法推斷出具體的名稱
// 若是依賴是必須的,直接拋出異常
// 若是依賴不是必須的,可是這個依賴類型不是集合或者數組,那麼也拋出異常
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(type, matchingBeans);
}
// 依賴不是必須的,可是依賴類型是集合或者數組,那麼返回一個null
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 直接找到了一個對應的Bean
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
// 前面已經說過了,這裏可能返回的是Bean的類型,因此須要進一步調用getBean
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
// 作一些檢查,若是依賴是必須的,查找出來的依賴是一個null,那麼報錯
// 查詢處理的依賴類型不符合,也報錯
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
findAutowireCandidates
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 簡單來講,這裏就是到容器中查詢requiredType類型的全部bean的名稱的集合
// 這裏會根據descriptor.isEager()來決定是否要匹配factoryBean類型的Bean
// 若是isEager()爲true,那麼會匹配factoryBean,反之,不會
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 第一步會到resolvableDependencies這個集合中查詢是否已經存在瞭解析好的依賴
// 像咱們之因此可以直接在Bean中注入applicationContext對象
// 就是由於Spring以前就將這個對象放入了resolvableDependencies集合中
for (Class<?> autowiringType : this.resolvableDependencies.keySet()) {
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = this.resolvableDependencies.get(autowiringType);
// 若是resolvableDependencies放入的是一個ObjectFactory類型的依賴
// 那麼在這裏會生成一個代理對象
// 例如,咱們能夠在controller中直接注入request對象
// 就是由於,容器啓動時就在resolvableDependencies放入了一個鍵值對
// 其中key爲:Request.class,value爲:ObjectFactory
// 在實際注入時放入的是一個代理對象
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
// 這裏放入的key不是Bean的名稱
// value是實際依賴的對象
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 接下來開始對以前查找出來的類型匹配的全部BeanName進行處理
for (String candidate : candidateNames) {
// 不是自引用,什麼是自引用?
// 1.候選的Bean的名稱跟須要進行注入的Bean名稱相同,意味着,本身注入本身
// 2.或者候選的Bean對應的factoryBean的名稱跟須要注入的Bean名稱相同,
// 也就是說A依賴了B可是B的建立又須要依賴A
// 要符合注入的條件
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 調用addCandidateEntry,加入到返回集合中,後文有對這個方法的分析
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 排除自引用的狀況下,沒有找到一個合適的依賴
if (result.isEmpty() && !indicatesMultipleBeans(requiredType)) {
// 1.先走fallback邏輯,Spring提供的一個擴展吧,感受沒什麼卵用
// 默認狀況下fallback的依賴描述符就是自身
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// fallback仍是失敗
if (result.isEmpty()) {
// 處理自引用
// 從這裏能夠看出,自引用的優先級是很低的,只有在容器中真正的只有這個Bean能做爲
// 候選者的時候,纔會去處理,不然自引用是被排除掉的
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
// 不是一個集合或者
// 是一個集合,可是beanName跟candidate的factoryBeanName相同
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
// candidates:就是findAutowireCandidates方法要返回的候選集合
// candidateName:當前的這個候選Bean的名稱
// descriptor:依賴描述符
// requiredType:依賴的類型
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
DependencyDescriptor descriptor, Class<?> requiredType) {
// 若是依賴是一個集合,或者容器中已經包含這個單例了
// 那麼直接調用getBean方法建立或者獲取這個Bean
if (descriptor instanceof MultiElementDescriptor || containsSingleton(candidateName)) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
}
// 若是依賴的類型不是一個集合,這個時候還不能肯定到底要使用哪一個依賴,
// 因此不能將這些Bean建立出來,因此這個時候,放入candidates是Bean的名稱以及類型
else {
candidates.put(candidateName, getType(candidateName));
}
}
處理屬性注入(@Autowired)
postProcessProperties
// 在applyMergedBeanDefinitionPostProcessors方法執行的時候,
// 已經解析過了@Autowired註解(buildAutowiringMetadata方法)
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 這裏獲取到的是解析過的緩存好的注入元數據
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 直接調用inject方法
// 存在兩種InjectionMetadata
// 1.AutowiredFieldElement
// 2.AutowiredMethodElement
// 分別對應字段的屬性注入以及方法的屬性注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
}
return pvs;
}
字段的屬性注入
// 最終反射調用filed.set方法
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
// 第一次注入的時候確定沒有緩存
// 這裏也是對原型狀況的處理
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
} else {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
// 這裏能夠看到,對@Autowired註解在字段上的處理
// 跟byType下自動注入的處理是同樣的,就是調用resolveDependency方法
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {
// 沒有緩存過的話,這裏須要進行緩存
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
// 註冊Bean之間的依賴關係
registerDependentBeans(beanName, autowiredBeanNames);
// 若是這個類型的依賴只存在一個的話,咱們就能肯定這個Bean的名稱
// 那麼直接將這個名稱緩存到ShortcutDependencyDescriptor中
// 第二次進行注入的時候就能夠直接調用getBean(beanName)獲得這個依賴了
// 實際上正常也只有一個,多個就報錯了
// 另外這裏會過濾掉@Vlaue獲得的依賴
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
// 經過resolvableDependencies這個集合找的依賴不知足containsBean條件
// 不會進行緩存,由於緩存實際仍是要調用getBean,而resolvableDependencies
// 是無法經過getBean獲取的
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { // 依賴描述符封裝成ShortcutDependencyDescriptor進行緩存
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
} else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
// 反射調用Field.set方法
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
方法的屬性注入
// 代碼看着很長,實際上邏輯跟字段注入基本同樣
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 判斷XML中是否配置了這個屬性,若是配置了直接跳過
// 換而言之,XML配置的屬性優先級高於@Autowired註解
if (checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
if (this.cached) {
arguments = resolveCachedArguments(beanName);
} else {
// 經過方法參數類型構造依賴描述符
// 邏輯基本同樣的,最終也是調用beanFactory.resolveDependency方法
Class<?>[] paramTypes = method.getParameterTypes();
arguments = new Object[paramTypes.length];
DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
Set<String> autowiredBeans = new LinkedHashSet<>(paramTypes.length);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
// 遍歷方法的每一個參數
for (int i = 0; i < arguments.length; i++) {
MethodParameter methodParam = new MethodParameter(method, i);
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
// 仍是要調用這個方法
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
arguments[i] = arg;
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
synchronized (this) {
if (!this.cached) {
if (arguments != null) {
Object[] cachedMethodArguments = new Object[paramTypes.length];
System.arraycopy(descriptors, 0, cachedMethodArguments, 0, arguments.length);
// 註冊bean之間的依賴關係
registerDependentBeans(beanName, autowiredBeans);
// 跟字段注入差很少,存在@Value註解,不進行緩存
if (autowiredBeans.size() == paramTypes.length) {
Iterator<String> it = autowiredBeans.iterator();
for (int i = 0; i < paramTypes.length; i++) {
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
descriptors[i], autowiredBeanName, paramTypes[i]);
}
}
}
this.cachedMethodArguments = cachedMethodArguments;
} else {
this.cachedMethodArguments = null;
}
this.cached = true;
}
}
}
if (arguments != null) {
try {
// 反射調用方法
// 像咱們的setter方法就是在這裏調用的
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
} catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
處理依賴檢查
protected void checkDependencies(
String beanName, AbstractBeanDefinition mbd, PropertyDescriptor[] pds, PropertyValues pvs)
throws UnsatisfiedDependencyException {
int dependencyCheck = mbd.getDependencyCheck();
for (PropertyDescriptor pd : pds) {
// 有set方法可是在pvs中沒有對應屬性,那麼須要判斷這個屬性是否要進行依賴檢查
// 若是須要進行依賴檢查的話,就須要報錯了
// pvs中保存的是自動注入以及XML配置的屬性
if (pd.getWriteMethod() != null && !pvs.contains(pd.getName())) {
// 是不是基本屬性,枚舉/日期等也包括在內
boolean isSimple = BeanUtils.isSimpleProperty(pd.getPropertyType());
// 若是DEPENDENCY_CHECK_ALL,對任意屬性都開啓了依賴檢查,報錯
// DEPENDENCY_CHECK_SIMPLE,對基本屬性開啓了依賴檢查而且是基本屬性,報錯
// DEPENDENCY_CHECK_OBJECTS,對非基本屬性開啓了依賴檢查而且不是非基本屬性,報錯
boolean unsatisfied = (dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_ALL) ||
(isSimple && dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_SIMPLE) ||
(!isSimple && dependencyCheck == AbstractBeanDefinition.DEPENDENCY_CHECK_OBJECTS);
if (unsatisfied) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, pd.getName(),
"Set this property value or disable dependency checking for this bean.");
}
}
}
}
將解析出來的屬性應用到Bean上
到這一步解析出來的屬性主要有三個來源
-
XML中配置的 -
經過byName的方式自動注入的 -
經過byType的方式自動注入的
可是在應用到Bean前還須要作一步類型轉換,這一部分代碼實際上跟咱們以前在Spring官網閱讀(十四)Spring中的BeanWrapper及類型轉換介紹的差很少,並且由於XML跟自動注入的方式都不常見,正常@Autowired
的方式進行注入的話,這個方法沒有什麼用,因此本文就再也不贅述。
總結
本文咱們主要分析了Spring在屬性注入過程當中的相關代碼,整個屬性注入能夠分爲兩個部分
-
@Autowired
/@Vale
的方式完成屬性注入 -
自動注入( byType
/byName
)
完成屬性注入的核心方法其實就是doResolveDependency
。doResolveDependency
這個方法的邏輯簡單來講分爲兩步:
-
經過依賴類型查詢到全部的類型匹配的bean的名稱 -
若是找到了多個的話,再根據依賴的名稱匹配對應的Bean的名稱 -
調用getBean獲得這個須要被注入的Bean -
最後反射調用字段的set方法完成屬性注入
從上面也能夠知道,其實整個屬性注入的邏輯是很簡單的。
若是本文對你有幫助的話,記得點個贊吧!
我叫DMZ,一個在學習路上匍匐前行的小菜鳥!
本文分享自微信公衆號 - 程序員DMZ(programerDmz)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。