1. 注入方式
-
構(gòu)造方法注入
- 對(duì)象構(gòu)造完恋捆,馬上可以使用
- 參數(shù)過(guò)長(zhǎng)維護(hù)復(fù)雜棵逊,無(wú)法繼承万矾,無(wú)默認(rèn)值
-
setter方法注入
- 方法可以命名悼吱,可以繼承,可以有默認(rèn)值
- 無(wú)法構(gòu)造完成后良狈,立馬使用
- 可以解決 scope = singleton 的bean 的循環(huán)依賴
- 提前暴露一個(gè)單例工廠方法后添,從而使其他bean能引用到該bean
- addSingletionFactory
- 提前暴露一個(gè)單例工廠方法后添,從而使其他bean能引用到該bean
-
接口注入
- 基本不用,強(qiáng)制實(shí)現(xiàn)不必要的接口
2. 兩種類型的容器
BeanFactory 和 ApplicationContext 繼承關(guān)系
-
BeanFactory 薪丁∮鑫鳎基礎(chǔ)類型IoC容器,提供完整的IoC服務(wù)支持窥突。如果沒有特殊指定努溃,默認(rèn)采用延
遲初始化策略(lazy-load)。 -
ApplicationContext 阻问。 ApplicationContext 在 BeanFactory 的基礎(chǔ)上構(gòu)建梧税,是相對(duì)比較高
級(jí)的容器實(shí)現(xiàn),除了擁有 BeanFactory 的所有支持称近, ApplicationContext 還提供了其他高級(jí)特性第队,比如事件發(fā)布、國(guó)際化信息支持等 刨秆,在該類型容器啟動(dòng)之后凳谦,默認(rèn)全部初始化并綁定完成。所以衡未,相對(duì)于 BeanFactory 來(lái)
說(shuō)尸执, ApplicationContext 要求更多的系統(tǒng)資源家凯,同時(shí),因?yàn)樵趩?dòng)時(shí)就完成所有初始化如失,容
器啟動(dòng)時(shí)間較之 BeanFactory 也會(huì)長(zhǎng)一些绊诲。在那些系統(tǒng)資源充足,并且要求更多功能的場(chǎng)景中褪贵,
ApplicationContext 類型的容器是比較合適的選擇掂之。
3. BeanFactory 的對(duì)象注冊(cè)與依賴綁定方式
直接編碼
BeanFactory 、 BeanDefinitionRegistry 以及 DefaultListableBeanFactory 的關(guān)系
- BeanFactory 定義獲取bean及bean的各種屬性脆丁,各個(gè) BeanFactory 的具體實(shí)現(xiàn)類負(fù)責(zé)具體Bean的注冊(cè)以及管理工作
-
BeanDefinition 每個(gè)bean 都有一個(gè)BeanDefinition 對(duì)應(yīng)世舰,保存對(duì)象的所有必要信息,包括其對(duì)應(yīng)的對(duì)象的class類型槽卫、是否是抽象
類跟压、構(gòu)造方法參數(shù)以及其他屬性等 - BeanDefinitionRegistry 定義對(duì)BeanDefinition的各種增刪改操作
外部配置文件方式
- Properties文件格式
- XML文件格式
- 如果需要可以引入自己的文件格式
注解方式
-
版本要求:Spring 2.5以及Java 5
或者更高版本的情況之下
4. bean 的 scope (面試:spring bean 支持哪幾種scope/作用域 )
<bean id="mockObject2" class="...MockBusinessObject"
scope="prototype"/>
scope 取值
-
singleton
- 對(duì)象實(shí)例數(shù)量: 一個(gè) 所有對(duì)該對(duì)象的引用將共享這個(gè)實(shí)例
- 生命周期: 從容器啟動(dòng),第一請(qǐng)求而初始化以后晒夹,將一直存活到容器退出
-
prototype
- 對(duì)象實(shí)例數(shù)量:多個(gè) 容器在接到該類型對(duì)象的請(qǐng)求的時(shí)候裆馒,會(huì)每次都重新生成一個(gè)新的對(duì)象實(shí)例給請(qǐng)求方
- 生命周期: 對(duì)象的實(shí)例化以及屬性設(shè)置等工作由容器負(fù)責(zé)的姊氓,但是只要準(zhǔn)備完畢丐怯,并且對(duì)象實(shí)例返回給請(qǐng)求方之后,容器就不再擁有當(dāng)前返回對(duì)象的引用翔横,請(qǐng)求方需要自己負(fù)責(zé)當(dāng)前返回對(duì)象的后繼生命周期的管理工作读跷,包括該對(duì)象的銷毀
-
request
- 對(duì)象實(shí)例數(shù)量: 多個(gè) 每個(gè)HTTP請(qǐng)求創(chuàng)建一個(gè)全新的 RequestProcessor 對(duì)象供當(dāng)前請(qǐng)求使用
- 生命周期: 當(dāng)請(qǐng)求結(jié)束后,該對(duì)象實(shí)例的生命周期即告結(jié)束
<bean id="requestProcessor" class="...RequestProcessor"
scope="request"/>
-
session
- 對(duì)象實(shí)例數(shù)量: 多個(gè) 每個(gè)獨(dú)立的session創(chuàng)建屬于它們自己的全新的 UserPreferences 對(duì)象實(shí)例
- 生命周期: session的生命周期
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
-
global session
- 對(duì)象實(shí)例數(shù)量:
- 生命周期: portlet的Web應(yīng)用程序中才有意義禾唁,它映射到portlet的global范圍的
session, 如果在普通的基于servlet的Web應(yīng)用中使用了這個(gè)類型的scope效览,容器會(huì)將其作為普通的session
類型的scope對(duì)待
<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>
- 自定義 scope ,可以根據(jù)自己的需要或者應(yīng)用的場(chǎng)景,來(lái)添加自定義的scope類型
5. BeanFactoryPostProcessor
-
作用: 允許我們?cè)谌萜鲗?shí)
例化相應(yīng)對(duì)象之前荡短,對(duì)注冊(cè)到容器的 BeanDefinition 所保存的信息做相應(yīng)的修改丐枉。,讓我們對(duì)最終的 BeanDefinition 做一些額外的操作掘托,比如修
改其中bean定義的某些屬性瘦锹,為bean定義增加其他信息等 例如 我們使用占位符配置數(shù)據(jù)庫(kù)相關(guān)信息,然后通過(guò)配置文件 配置實(shí)際的值闪盔。
6. bean的生命周期
graph TB
實(shí)例化bean對(duì)象-->設(shè)置對(duì)象屬性
設(shè)置對(duì)象屬性-->檢查Aware相關(guān)接口并設(shè)置相關(guān)依賴
檢查Aware相關(guān)接口并設(shè)置相關(guān)依賴-->beanPostProcessor前置處理
beanPostProcessor前置處理-->檢查是否是InitializingBean以決定是否調(diào)用afterPropertiesSet
檢查是否是InitializingBean以決定是否調(diào)用afterPropertiesSet-->檢查是否配置有自定義init-method
檢查是否配置有自定義init-method-->beanPostProcessor后置處理
beanPostProcessor后置處理-->注冊(cè)必要的Destruction相關(guān)回調(diào)接口
注冊(cè)必要的Destruction相關(guān)回調(diào)接口-->使用中
使用中-->是否實(shí)現(xiàn)DisPosableBean接口
是否實(shí)現(xiàn)DisPosableBean接口-->是否配置有自定義的destory方法
6.1 實(shí)例化bean對(duì)象弯院,設(shè)置對(duì)象屬性
- 容器在內(nèi)部實(shí)現(xiàn)的時(shí)候,采用“策略模式(Strategy Pattern)”來(lái)決定采用何種方式初始化bean實(shí)例泪掀。
通常听绳,可以通過(guò)反射或者CGLIB動(dòng)態(tài)字節(jié)碼生成來(lái)初始化相應(yīng)的bean實(shí)例或者動(dòng)態(tài)生成其子類 - 容器根據(jù)BeanDefintion 取得實(shí)例化信息,結(jié)合CglibSubclassingInstantiationStrategy策略以及不同的bean定義類型异赫,就可以返回實(shí)例化完成的對(duì)象實(shí)例
- 根據(jù)beandefinition 有沒有l(wèi)ookup-override或者replace-override屬性 判斷是否用 cglib策略
- 返回 BeanWrapper 對(duì)構(gòu)造完成的對(duì)象實(shí)例進(jìn)行包裹椅挣,返回相應(yīng)的 BeanWrapper 實(shí)例
- 通過(guò)BeanWrapper設(shè)置對(duì)象屬性头岔,免去直接使用Java反射API,java反射很多異常要處理
6.2 檢查Aware相關(guān)接口并設(shè)置相關(guān)依賴
- 當(dāng)對(duì)象實(shí)例化完成并且相關(guān)屬性以及依賴設(shè)置完成之后鼠证,Spring容器會(huì)檢查當(dāng)前對(duì)象實(shí)例是否實(shí)
現(xiàn)了一系列的以 Aware 命名結(jié)尾的接口定義切油。如果是,則將這些 Aware 接口定義中規(guī)定的依賴注入給當(dāng)前對(duì)象實(shí)例名惩。- org.springframework.beans.factory.BeanNameAware 澎胡。如果Spring容器檢測(cè)到當(dāng)前對(duì)象實(shí)
例實(shí)現(xiàn)了該接口,會(huì)將該對(duì)象實(shí)例的bean定義對(duì)應(yīng)的 beanName 設(shè)置到當(dāng)前對(duì)象實(shí)例娩鹉。 - org.springframework.beans.factory.BeanClassLoaderAware 攻谁。如果容器檢測(cè)到當(dāng)前對(duì)
象實(shí)例實(shí)現(xiàn)了該接口,會(huì)將 對(duì)應(yīng)加載當(dāng)前 bean的Classloader注入當(dāng)前對(duì)象實(shí)例弯予。默認(rèn)會(huì)使用
加載org.springframework.util.ClassUtils類的Classloader戚宦。 - org.springframework.beans.factory.BeanFactoryAware 。在介紹方法注入的時(shí)候锈嫩,我們
提到過(guò)使用該接口以便每次獲取prototype類型bean的不同實(shí)例受楼。如果對(duì)象聲明實(shí)現(xiàn)了
BeanFactoryAware 接口, BeanFactory 容器會(huì)將自身設(shè)置到當(dāng)前對(duì)象實(shí)例呼寸。這樣艳汽,當(dāng)前對(duì)象
實(shí)例就擁有了一個(gè) BeanFactory 容器的引用,并且可以對(duì)這個(gè)容器內(nèi)允許訪問(wèn)的對(duì)象按照需要
進(jìn)行訪問(wèn)对雪。 - ApplicationContext 很多 Aware 接口通過(guò)BeanPostProcessor 實(shí)現(xiàn) 如下ApplicationContextAwareProcessor的postProcessBeforeInitialization方法
- org.springframework.beans.factory.BeanNameAware 澎胡。如果Spring容器檢測(cè)到當(dāng)前對(duì)象實(shí)
package org.springframework.context.support;
class ApplicationContextAwareProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
ApplicationContextAwareProcessor.this.invokeAwareInterfaces(bean);
return null;
}
}, acc);
} else {
this.invokeAwareInterfaces(bean);
}
return bean;
}
}
6.3 beanPostProcessor
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;
Object postProcessAfterInitialization (Object var1, String var2) throws BeansException;
}
- postProcessBeforeInitialization 前置處理
- postProcessAfterInitialization 后置處理
- 可以自定義beanPostProcessor 處理
public class PasswordDecodePostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object object, String beanName)
throws BeansException {
return object;
}
public Object postProcessBeforeInitialization(Object object, String beanName)
throws BeansException {
if(object instanceof 我們想要處理的bean.class)
{
// 設(shè)置屬性河狐,加密解密等。
}
return object;
}
}
6.4 InitializingBean瑟捣,init-method
package org.springframework.beans.factory;
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
-
InitializingBean
-
作用: 在對(duì)象實(shí)例化過(guò)程調(diào)用過(guò)“ BeanPostProcessor 的前置處理”
之后馋艺,會(huì)接著檢測(cè)當(dāng)前對(duì)象是否實(shí)現(xiàn)了 InitializingBean 接口,如果是迈套,則會(huì)調(diào)用其 afterPropertiesSet() 方法進(jìn)一步調(diào)整對(duì)象實(shí)例的狀態(tài)捐祠。 -
場(chǎng)景: 在有些情況下,某個(gè)業(yè)務(wù)對(duì)象實(shí)例化完成后桑李,還
不能處于可以使用狀態(tài)踱蛀。這個(gè)時(shí)候就可以讓該業(yè)務(wù)對(duì)象實(shí)現(xiàn)該接口,并在方法 afterPropertiesSet()
中完成對(duì)該業(yè)務(wù)對(duì)象的后續(xù)處理 如圖片驗(yàn)證碼攔截器 在實(shí)例化之后芙扎,通過(guò)afterPropertiesSet 從配置中讀取要攔截的路徑
-
作用: 在對(duì)象實(shí)例化過(guò)程調(diào)用過(guò)“ BeanPostProcessor 的前置處理”
-
init-method
-
作用: 自定義初始化操作可以以任何方式命名星岗,還可以通
過(guò)最頂層的 <beans> 的 default-init-method 統(tǒng)一指定。 - 場(chǎng)景: InitializingBean 一樣
-
作用: 自定義初始化操作可以以任何方式命名星岗,還可以通
- 對(duì)比:InitializingBean 業(yè)務(wù)對(duì)象實(shí)現(xiàn)這個(gè)接口戒洼,有侵入性 init-method 就沒有這個(gè)問(wèn)題
6.5 注冊(cè)必要的Destruction(一次性)相關(guān)回調(diào)接口
- bean 使用前還有注冊(cè)一些相關(guān)回調(diào)接口
6.6 DisposableBean俏橘,destroy-method
package org.springframework.beans.factory;
public interface DisposableBean {
void destroy() throws Exception;
}
-
作用: 為該實(shí)例注冊(cè)一個(gè)用于對(duì)象銷毀的回調(diào)(Callback),以便在這些singleton類型的對(duì)象實(shí)例銷毀之
前圈浇,執(zhí)行銷毀邏輯寥掐。只有該對(duì)象實(shí)例不再被使用的時(shí)候靴寂,
才會(huì)執(zhí)行相關(guān)的自定義銷毀邏輯,此時(shí)通常也就是Spring容器關(guān)閉的時(shí)候 - 執(zhí)行對(duì)象的自定義銷毀方法
- BeanFactory destroySingletons()
- ApplicationContext registerShutdownHook() 使用了addShutdownHook()
//m中增加一個(gè)關(guān)閉的鉤子召耘,當(dāng)jvm關(guān)閉的時(shí)候百炬,會(huì)執(zhí)行系統(tǒng)中已經(jīng)設(shè)置的所有通過(guò)方法addShutdownHook添加的鉤子,當(dāng)系統(tǒng)執(zhí)行完這些鉤子后污它,jvm才會(huì)關(guān)閉剖踊。所以這些鉤子可以在jvm關(guān)閉的時(shí)候進(jìn)行內(nèi)存清理、對(duì)象銷毀等操作衫贬。
Runtime.getRuntime().addShutdownHook(Thread hook)