目錄
SpringBean的生命周期
Bean實例屬性填充
三級緩存
常用的Aware接口
Spring IoC容器實例化Bean總結
SpringBean的生命周期
Spring Bean的生命周期是從 Bean 實例化之后,即通過反射創建出對象之后,到Bean成為一個完整對象,最終存儲到單例池中,這個過程被稱為Spring Bean的生命周期。Spring Bean的生命周期大體上分為三個階段:
- Bean的實例化階段:Spring框架會取出BeanDefinition的信息進行判斷當前Bean的范圍是否是singleton,是否不是延遲加載的,是否不是FactoryBean等,最終將一個普通的singleton的Bean通過反射進行實例化;
- Bean的初始化階段:Bean創建之后還僅僅是個"半成品",還需要對Bean實例的屬性進行填充、執行一些Aware接口方法、執行BeanPostProcessor方法、執行InitializingBean接口的初始化方法、執行自定義初始化init方法等。該階段是Spring最具技術含量和復雜度的階段,Aop增強功能,Spring的注解功能等。以及Bean的循環引用問題都是在這個階段體現的。
- Bean的完成階段:經過初始化階段,Bean就成為了一個完整的Spring Bean,被存儲到單例池singletonObjects中去。即完成了Spring Bean的整個生命周期。
接下來我們著重于Bean的初始化階段進行分析,初始化過程涉及如下幾個過程:
- Bean實例的屬性填充
- Aware接口屬性注入
- BeanPostProcessor的before()方法回調
- InitializingBean接口的初始化方法回調
- 自定義初始化方法inti回調
- BeanPostProcessor的after()方法回調
Bean實例屬性填充
基于xml文件的實例屬性填充。
<bean id="userService" class="com.zmt.service.impl.UserServiceImpl"><property name="userDao" ref="userDao"></property><property name="name" value="張三"></property>
</bean>
在屬性注入中,存在三種情況:
- 一種基本屬性注入,通過反射拿到set方法直接注入
- 一種單項引用屬性注入,如UserService中需要注入UserDao,但UserDao不需要UserService,這種從容器中執行getBean方法后通過set方法反射進去,如果容器中不存在,則先創建被注入的對象后再進行諸如操作。
- 一種雙向對象屬性注入,也就是說,UserService中需要注入UserDao,UserDao需要注入UserService。這涉及到循環引用。
下面是循環引用的問題流程圖
如果循環依賴的話,半成品的bean會被存儲在內存中,不歸Spring管控,那么在注入時,就無法從容器中獲取到對應的bean,從而導致死循環不停的創建對象。解決方法是,在Spring中添加一個存儲半成品bean的map,當無法從單例池中獲取的對象時,從半成品中的map獲取
三級緩存
所謂三級緩存,分別是單例池與兩個存儲半成品bean的map集合,在源碼中為
這三個Map集合,分別存儲的是:
- 實例化與初始化都完成的bean,稱為一級緩存
- 緩存半成品,且對象已經被其他對象引用了,稱為二級緩存
- 緩存半成品,對象也未被引用,使用時在通過工廠創建bean,稱為三級緩存
UserService和UserDao循環依賴的過程結合上述三級緩存描述一下就是
- UserService 實例化對象,但尚未初始化,將UserService存儲到三級緩存;
- UserService 屬性注入,需要UserDao,從緩存中獲取,沒有UserDao;
- UserDao實例化對象,但尚未初始化,將UserDao存儲到到三級緩存;
- UserDao屬性注入,需要UserService,從三級緩存獲取UserService,UserService從三級緩存移入二級緩存;
- UserDao執行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存;
- UserService 注入UserDao;
- UserService執行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存。
常用的Aware接口
Aware接口是一種框架輔助屬性注入的一種思想,其他框架中也可以看到類似的接口。框架具備高度封裝性,我們接觸到的一般都是業務代碼,一個底層功能API不能輕易的獲取到,但是這不意味著永遠用不到這些對象,如果用到了就可以使用框架提供的類似Aware的接口,讓框架給我們注入該對象。
Aware接口 | 回調方法 | 作用 |
ServletContextAware | setServletContext(ServletContext context) | Spring框架回調方法注入ServletContext,web環境下才生效 |
BeanFactoryAware | setBeanFactory(BeanFactory factory) | Spring框架回調方法注入beanFactory對象 |
BeanNameAware | setBeanName(String beanName) | Spring框架回調方法注入當前Bean在容器中的beanName |
ApplicationContextAware | setApplicationContext(Application application) | Spring框架回調方法注入ApplicationContext對象 |