@Autowired淺析

@Autowired淺析

首先放幾段代碼和幾個問題,帶着思考去看接下來的結論

第一個問題

第一段代碼:容器初始化完畢,控制檯是否會打印(“This is a method from TeachService”)這句話?

@Service
public class StudyService {


	public void setTeacherService(TeachService teacherService){
		teacherService.teach();
	}

}


@Service
public class TeachService {

	public void teach(){
		System.out.println("This is a method from TeachService");
	}


}

答案是會,但是這裏我是做了一個細節上的配置,正常情況下,即默認情況是不會打印的,稍後細說。

在這裏插入圖片描述

第二個問題

說起@Autowired註解,大家想到的就是byType,那麼看下面的代碼。

//聲明一個接口
public interface People {
	void showIdentity();
}
//寫兩個實現類,都注入到spring容器中
@Service
public class StudyService implements People {
	@Override
	public void showIdentity() {
		System.out.println("I am a student");
	}
}

@Service
public class TeachService implements People {
	@Override
	public void showIdentity() {
		System.out.println("I am a teacher");
	}
}
//使用另外的bean注入People類型,請注意,這裏注入的類型是接口,變量名使用的是studyService
//如果按照byType的理解,容器初始化時應該會報錯,同一個type找到多個bean,不知道注入哪個
@Service
public class Leader {
	@Autowired
	People studyService;
	public void showYourIdentity(){
		studyService.showIdentity();
	}
}

其實呢,看下圖運行成果

在這裏插入圖片描述

第三個問題

讀過源碼的同學可能瞭解過populateBean方法裏有一段判斷邏輯

在這裏插入圖片描述

這裏的邏輯是判斷bean的注入類型是否爲byName或者byType,看到圖中的值,相信大家都知道,是不會進這個if分支的,那麼是爲什麼呢?接下來放一段官網對於注入的一個解釋。

在這裏插入圖片描述

下面是對於上面的一個部分翻譯

模式 解釋
no 非自動裝配,bean的應用需要通過ref元素定義
byName 按屬性名稱自動裝配。Spring容器會尋找與需要自動實現的屬性同名的bean。
byType 如果容器中恰好存在該屬性類型的一個bean,則允許該屬性被自動調用。如果存在多個,就會拋出一個異常,這表明不能對該bean使用byType自動裝配。
constructor 類似於byType,但適用於構造函數參數。

問題解答

按照上述官網解釋,如果@Autowired註解真的是像大部分網上所說的byType,那麼我第二個問題的代碼怎麼可能運行成功呢?接下來用spring的後置處理器去獲取一下StudyService的BeanDefinition對象,通過BeanDefinition對象查看裝配類型究竟是什麼吧!

@Configuration
public class MyPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		GenericBeanDefinition s = (GenericBeanDefinition) beanFactory.getBeanDefinition("studyService");
		System.out.println("默認裝配類型:"+s.getAutowireMode());
	}
}

在這裏插入圖片描述

由上圖可知@Autowired的裝配類型爲0,即官網所說的NO-非自動裝配。

有的人可能疑問了,爲什麼叫非自動裝配?spring明明幫我們把需要的類創建出來了呀,這個問題接下來會解釋。

先回顧第一個問題,爲什麼明明沒有使用註解和xml,set方法中的bean依舊注入成功了呢?依舊用到了後置處理器。上代碼

@Configuration
public class MyPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		GenericBeanDefinition s = (GenericBeanDefinition) beanFactory.getBeanDefinition("studyService");
        //重點在這裏,通過後置處理器得到BeanDefinition對象後,修改autowireMode的值爲2,即byType
		s.setAutowireMode(2);
	}
}

在這裏插入圖片描述

怎麼做到的已經展示完了,接下來結合這一和二的內容,給大家做一個簡短的解釋。

首先大家所理解的自動裝配,是以開發人員的角度來說:我是一個開發,spring幫我把TeachService創建並注入到了StudyService中,這個過程中,“我”並沒有參與什麼,只是聲明瞭一個註解。

這就好比:

​以前我們大家喫飯,需要自己買菜->做飯->喫飯->洗碗,做完整個週期性的任務纔算完成;

​現在有了餐館(spring),我們只需要到餐館(spring)聲明我要喫魚香肉絲,在(買菜->做飯->喫飯->洗 碗)這個週期中,我們只需做到“喫飯”即可。

請注意,上述描述的角度是我->餐館的顧客|開發人員->spring的使用者

不知道大家能不能明白我所說的。

接下來的是我個人理解了,可能有所錯誤,大家可以共同探討!!!

我理解的自動裝配是相對於spring角度,也就是餐館角度;

當我走進餐館時(我使用setTeachService方法),老闆看到我就“覺得”我想要魚香肉絲(對應autowiredMode修改爲2之後,spring容器發現setTeachService方法時),並沒有問我是否真的需要(比如我就是想單純實現一個setTeachService方法自己用呢,對吧),就直接給我上了一盤魚香肉絲飯。

簡單的來說:在autowiredMode不等於0時,當開發人員提供了一個spring認可的注入方式,即set和construct形式時,spring會直接注入這兩種DI形式中的bean(前提是bean)

這裏插一個小知識點

官方文檔說明了,DI(依賴注入)有兩種主要的變體,即基於構造器的依賴注入和基於setter的依賴注入。

即使是常用的@Autowired註解,也是通過反射生成set方法進行的賦值。

在這裏插入圖片描述

本菜鳥也是剛入行三年,如果上述有什麼問題,大家可以留言,我會積極改正和學習的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章