Spring原始碼(2)注入
阿新 • • 發佈:2021-07-12
Spring採用IoC的思想,實現IoC思想的關鍵在於採用了
注入
的方式進行控制反轉,在Spring中,注入有很多形式,這裡只說明依賴注入
、方法注入
、自動注入
三種。
1 依賴注入
根據官網介紹,依賴注入主要分為兩種方式
- 建構函式注入
- Setter方法注入
1.1 建構函式注入
@Component
public class OneDao {
public OneDao() {
System.out.println("Dao無參建構函式已經呼叫");
}
}
@Component public class OneService { private OneDao oneDao; public OneService() { System.out.println("OneService無參建構函式已經被呼叫"); } public OneService(OneDao oneDao) { System.out.println("OneService正在使用建構函式注入oneDao"); this.oneDao = oneDao; System.out.println("OneService有參建構函式已經被呼叫"); } public void test(){ System.out.println(oneDao); } }
@Configuration
public class Config {
@Bean
public OneDao oneDao(){
OneDao oneDao = new OneDao();
return oneDao;
}
@Bean
public OneService oneService(){
OneService oneService = new OneService(oneDao());
return oneService;
}
}
public class ComponentMain { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class); OneService oneService = (OneService) applicationContext.getBean("oneService"); System.out.println(oneService); } }
1.2 setter注入
@Component
public class OneDao {
public OneDao() {
System.out.println("Dao無參建構函式已經呼叫");
}
}
@Component public class OneService { private OneDao oneDao; public OneService() { System.out.println("OneService無參建構函式已經被呼叫"); } public void test(){ System.out.println(oneDao); } @Autowired //一定要加@Autowired ,否則預設不進行set注入 public void setOneDao(OneDao oneDao) { System.out.println("正在使用setter進行注入OneDao"); this.oneDao = oneDao; } }
@Configuration
public class Config {
@Bean
public OneDao oneDao(){
OneDao oneDao = new OneDao();
return oneDao;
}
@Bean
public OneService oneService(){
OneService oneService = new OneService();
return oneService;
}
}
public class ComponentMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
OneService oneService = (OneService) applicationContext.getBean("oneService");
System.out.println(oneService);
}
}
tips:
@Autowired
直接加到欄位上跟加到set方法上有什麼區別?為什麼我們驗證的時候需要將其新增到setter方法上?
- 直接新增
@Autowired
註解到欄位上,不需要提供setter方法也能完成注入。
1.3 同時採用構造注入加setter注入
構造注入在bean例項化階段完成了,而後會呼叫setter注入,會對前面的構造注入進行覆蓋。
2 方法注入
方法注入,是為了解決原型失效的問題。不管是setter注入還是建構函式注入,已經完成了該bean的依賴注入,後續不能進行依賴的修改。在使用該bean的時候,獲得的還是依賴屬性的單例,這樣就失去了原型的作用。為了解決這個問題,出現了方法注入,在方法中對原型的bean進行重新獲取和注入。
問題:
@Component
@Scope("prototype")
public class OneDao {
public OneDao() {
System.out.println("Dao無參建構函式已經呼叫");
}
int i;
public void addAndPrint(int a){
i = i + a;
System.out.println(i);
}
}
@Component
public class OneService {
@Autowired
private OneDao oneDao;
public OneService() {
System.out.println("OneService無參建構函式已經被呼叫");
}
public void test(int a){
oneDao.addAndPrint(a);
}
}
@Configuration
public class Config {
@Bean
public OneDao oneDao(){
OneDao oneDao = new OneDao();
return oneDao;
}
@Bean
public OneService oneService(){
OneService oneService = new OneService();
return oneService;
}
}
public class ComponentMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Config.class);
OneService oneService = (OneService) applicationContext.getBean("oneService");
oneService.test(1);
oneService.test(2);
oneService.test(3);
}
}
問題:本來定義了OneDao類是一個原型的類,那麼在OneService中應該獲取的都是最新的OneDao物件,然後再呼叫其中的方法,預期結果應該是1,2,3,但是真是結果是1,3,6,這因為在OneService中已經完成OneDao的依賴注入,在測試的時候使用的始終是一個OneDao物件。
解決這個問題,就可以通過方法注入
的方式,每次都獲取最新的OneDao物件
即可。
-
通過注入applicationContext物件
@Component public class OneService{ @Autowired private ApplicationContext applicationContext; public OneService() { System.out.println("OneService無參建構函式已經被呼叫"); } public void test(int a){ OneDao oneDao = ((OneDao) applicationContext.getBean("oneDao")); oneDao.addAndPrint(a); } }
-
通過@LookUp的方式
@Component
public class OneService{
public OneService() {
System.out.println("OneService無參建構函式已經被呼叫");
}
public void test(int a){
OneDao oneDao = lookUp();
oneDao.addAndPrint(a);
}
@Lookup
public OneDao lookUp(){
return null;
}
}
3 自動注入
自動注入和精確注入:所謂精確注入就是指通過建構函式或者setter方法指定了我們物件之間的依賴,也就是依賴注入,然後Spring根據我們指定的依賴關係,精確的給我們完成了注入。
那麼自動注入就是spring根據型別或者beanName自動幫我們進行注入。
注入模型:
官網給我們介紹了自動注入的四種模型,如圖: