- Spring原始碼系列:BeanDefinition原始碼解析
- Spring原始碼系列:BeanDefinition載入(上)
- Spring原始碼系列:BeanDefinition載入(中)
- Spring原始碼系列:BeanDefinition載入(下)
在上面四篇文章中大概分析了一下Bean的載入,其實這個過程就是在Ioc容器中建立BeanDefinition的資料對映。但是對於Bean的例項化並未涉及,在之前的分析中也提到,bean的例項化是在依賴注入是才具體完成。
關於依賴注入
關於Spring,我們最先想到的就兩個Ioc和Aop;然後關於Ioc我們又能牽扯出兩個:控制反轉和依賴注入。 控制反轉和依賴注入在網上被無數大神亦或菜鳥解讀過,這裡就不羅列那些概念了,直接看:
不使用Spring
public class UserService {
//手動new一個
UserDao userDao = new UserDaoImpl();
public int insertUser(String userName) {
return userDao.insertUser(userName);
}
}
複製程式碼
使用Spring(以註解方式)
public class UserService {
@Autowired
private UserDao userDao;
public int insertUser(String userName) {
return userDao.insertUser(userName);
}
}
複製程式碼
看起來貌似沒有啥很大的改變,區別呢?
我們先來分析下在一個類中這兩種申明的區別:
UserDao userDao;
userDao是UserDao型別的引用名稱。僅僅是宣告瞭一個變數引用名稱。並沒有做例項化,userDao的例項化可以通過set方法進行設定(Spring中之前常用的就是set方法注入);當我們初始化持有userDao的這個類時我們還不知道userDao到底具體指向哪個堆中的物件地址。
UserDao userDao = new UserDaoImpl();
而這個,申明一個變數名稱,並將userDao直接指向new UserDaoImpl()建立的物件。
我們來看Spring中關於注入之後物件地址以及不使用注入方式物件的地址:
1、直接注入
2、注入覆蓋了我自己的物件 3、自己手動new通過上面三幅圖可以明顯的看出,自己手動new的物件沒有使用代理的方式,而託管給Spring注入的物件均是通過動態代理來完成的。
關於動態代理:《豬弟拱Java》連載番外篇:Java代理(中)
總結:當某個角色(可能是一個Java例項,呼叫者)需要另一個角色(另一個Java例項,被呼叫者)的協助時,在未使用Spring來管理Bean的程式設計過程中,通常由呼叫者來建立被呼叫者的例項。但在Spring裡,建立被呼叫者的工作不再由呼叫者來完成,因此稱為控制反轉;建立被呼叫者例項的工作通常由Spring容器來完成,然後注入呼叫者,因此也稱為依賴注入。
三個問題
那麼現在要考慮問題就是,什麼時候會觸發我們的依賴注入呢?Bean的例項化是否必須在依賴注入時才能完成呢?在Spring中又是通過哪些類來完成注入工作的呢?
1、什麼時候會觸發我們的依賴注入
答:使用者第一次向容器獲取Bean的時候出發。
2、Bean的例項化是否必須在依賴注入時才能完成
這個其實不是必須的,我們們都知道BeanDefinition中有lazy-init這樣一個屬性,我們可以通過控制這個屬性的設定來讓容器完成對Bean的預例項化。預例項化就是說它的依賴注入是在例項化過程中完成的。
第一和第二個問題將會在分析第三個問題的時候慢慢的細化分析。所以第三個問題其實沒啥鳥用,但也是最最最核心的,就是為了引出後面關於一些具體類的分析的。