spring--擴充套件點
擴充套件點:
BeanFactoryPostProcessor構建 BeanFactory後呼叫,此時BeanFactory , BeanDefinition 已經解析完畢。
BeanPostProcessor初始化 Bean 物件時呼叫,所有bean的構建都會呼叫這個介面的兩個方法。兩個方法引數傳入的bean屬性都已經注入完畢。
InitializingBeanBean 例項建立後,所有的屬性注入完畢後呼叫。
定義bean時可以指定init-method 和 destory-method 方法
InstantiationAwareBeanPostProcessor bean包裝類初始化時呼叫方法
DisposableBeanBean 例項銷燬時呼叫
擴充套件點呼叫順序:
1、呼叫 BeanFactoryPostProcessor 子類的 postProcessBeanFactory() 方法(工廠必須先建立),這裡beanFactory 已經建立,beanDefinition已經解析完畢。
2、呼叫bean 的構造方法。屬性沒有初始化(使用的都是預設值),依賴沒有注入。
3、呼叫 BeanPostProcessor.postProcessBeforeInitialization() 方法。(所有bean初始化都會呼叫)
4、呼叫 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法。(所有bean初始化都會呼叫)
5、呼叫bean 定義的 init-method 方法(具體到某個bean的初始化)。
6、如果bean 實現了 InitializingBean 介面,呼叫 InitializingBean.afterPropertiesSet() 方法(具體到某個bean的初始化)。
7、呼叫 BeanPostProcessor.postProcessAfterInitialization() 方法。(所有bean初始化都會呼叫)
8、呼叫 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法。(所有bean初始化都會呼叫)
9、bean 銷燬,先呼叫 destory-method 方法,如果bean實現了DisposableBean介面,再呼叫DisposableBean.destroy() 方法。
1、BeanFactoryPostProcessor
此介面只有一個方法:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
所以就是使用ConfigurableListableBeanFactory 進行擴充套件。
擴充套件方式:
這個擴充套件的地方就是呼叫 ConfigurableListableBeanFactory 方法進行擴充套件。
ConfigurableListableBeanFactory 可以分析和修改、預初始化單例Bean,並且可以修改已有的BeanDifinition屬性和型別
呼叫地方:
所有實現介面BeanFactoryPostProcessor 的bean 都在這裡被呼叫
AbstractApplicationContext.invokeBeanFactoryPostProcessors(beanFactory);
使用場景:
修改bean definition
修改注入型別的注入例項
ConfigurableListableBeanFactory 原始碼分析:
public interface ConfigurableListableBeanFactory
extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
/**
* 忽略給定型別依賴的自動注入
*/
void ignoreDependencyType(Class<?> type);
/**
* 忽略給定介面型別的自動注入
* 這種特定方式通常被用於使用其它方式解決應用上下文依賴註冊。如:BeanFactory通過 BeanFactoryAware 註冊,ApplicationContext 通過 ApplicationContextAware 來註冊。
* 預設情況只有 BeanFactoryAware 介面是被忽略的。呼叫此方法忽略介面依賴自動注入。
*/
void ignoreDependencyInterface(Class<?> ifc);
/**
* 指定依賴的型別,使用 autowiredValue 物件注入。
* 預留給 factory/context 型別注入,但是工廠中沒有這類bean 定義。
*/
void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
/**
* 確定指定bean是否有自動注入的資格,被注入到宣告依賴匹配的類的其它bean中
*/
boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException;
/**
* 獲取bean 的 BeanDefinition,可以訪問屬性值和構造方法引數。
* 返回值不是一個副本,是註冊在factory中原始的definition object。意味著可以修改為其它更多的特定型別。
*/
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
/**
* 獲取factory 管理所有bean 的beanName的統一檢視。
*/
Iterator<String> getBeanNamesIterator();
/**
* 清除merged bean 定義快取,刪除那些沒有資格進行完整元資料快取的bean。
* 當解析的bean definitions被修改了,如呼叫了 BeanFactoryPostProcessor 方法修改了bean definition。
* 注意:此時的bean的元資料對已經建立的bean,是要保留的。
*/
void clearMetadataCache();
/**
* 凍結所有的 bean definition, 不讓在後面處理修改。
*/
void freezeConfiguration();
/**
* 查詢 Configuration 是否被凍結
*/
boolean isConfigurationFrozen();
/**
* 確保所有的非惰性單例(non-lazy-init singletons)全部例項化。用於解決迴圈依賴問題。
* 如果需要,通過在factory 設定完成時呼叫
*/
void preInstantiateSingletons() throws BeansException;
}
在spring 原始碼中有使用 ConfigurableListableBeanFactory 類的方法:AbstractApplicationContext.refresh() 方法中呼叫的prepareBeanFactory() 方法。
如:PropertyResourceConfigurer 就是一個內建的BeanFactoryPostProcessor實現,實現類是PropertySourcesPlaceholderConfigurer。
測試:
依賴介面及實現/**
* 依賴介面
*/
public interface TestServerInterface {
void m();
}
@Component
public class TestServer2 implements TestServerInterface {
@Autowired
private Other o;
@Override
public void m() {
System.out.println("this is server2");
}
public Other getO() {
return o;
}
public void setO(Other o) {
this.o = o;
}
}
介面實現類依賴的Other 類:
@Component
public class Other {
public void m(){
System.out.println("other m");
}
}
TestServer 依賴 TestServerInterface 子類
@Component
public class TestServer {
private String name="default";
@Autowired
private TestServerInterface t;
public void test(){
t.m();
System.out.println("spring extend test");
}
@PostConstruct
public void before(){
System.out.println("init-method........");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestServerInterface getT() {
return t;
}
public void setT(TestServerInterface t) {
this.t = t;
}
}
BeanFactoryPostProcessor 實現類
/**
* 構建 BeanFactory 完成後呼叫,此時beanFactory 已經建立,beanDefinition已經解析完畢。
*
* 可以修改bean
* 可以獲取beandefinition,修改bean 的配置
*
* 引數是ConfigurableListableBeanFactory,體現了不同BeanFactory
*/
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor------------");
/**
* 修改注入型別
* 如果此bean還依賴其它的bean的話,那麼依賴的bean是null,因為 finishBeanFactoryInitialization 組建bean之間的關係是在這個方法中呼叫的。
*/
TestServerInterface t = (TestServerInterface)configurableListableBeanFactory.getBean("testServer2");
configurableListableBeanFactory.registerResolvableDependency(TestServerInterface.class, t);
//手動注入Other 物件
TestServer2 t2 = (TestServer2)t;
t2.setO(configurableListableBeanFactory.getBean(Other.class));
/**
* 修改bean 屬性
*/
//修改beandefinition 的屬性注入
BeanDefinition tb = configurableListableBeanFactory.getBeanDefinition("testServer");
MutablePropertyValues propertyValues = tb.getPropertyValues();
propertyValues.addPropertyValue("name","new name");
System.out.println("BeanFactoryPostProcessor############");
}
}
測試程式碼(省)
測試總結:
測試:
1、獲取testServer ,testServer 的name值被修改為 new name
2、介面TestServerInterface 如果有兩個實現類,那麼啟動時就不知道要注入那一個,在postProcessBeanFactory 方法中,定義了此介面使用 name 為 testServer2 的bean 注入,就解決了這個問。
3、在 postProcessBeanFactory()方法中獲取bean,如果還依賴其它的bean的話,那麼依賴的bean是不會被注入的,這個時候就要手動注入了要麼也呼叫一下 configurableListableBeanFactory.registerResolvableDependency() 方法,因為 finishBeanFactoryInitialization()方法才是組建bean之間的關係的地方。(見程式碼手動注入Other)
4、如果有多個BeanFactoryPostProcessor型別的bean,可以使用 @Order()註解來指定呼叫順序。
2、BeanPostProcessor
初始化 Bean 物件時呼叫,所有bean的構建都會呼叫這個介面的兩個方法。兩個方法引數傳入的bean屬性都已經注入完畢。使用場景:
可以修改bean的屬性,
可以給bean生成一個動態代理例項等等。一些Spring AOP的底層處理也是通過實現BeanPostProcessor來執行代理包裝邏輯的。
BeanPostProcessor 原始碼分析:
public interface BeanPostProcessor {
/**
* 所有 bean 初始化之前呼叫,bean屬性已經被填充,所有屬性及依賴全部注入。
* 返回的bean包裝類或者是原始bean。
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 所有 bean 初始化之後呼叫。所有屬性及依賴全部注入。
* 傳入的bean屬性已經被填充。
* 返回的bean包裝類或者是原始bean。
* 從spring 2.0開始,FactoryBean 會被呼叫兩次,一次是FactoryBean 本身,一次是getObject() 建立bean。
*
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
這兩個方法區別就是被呼叫的地方不同,一個是呼叫bean init-method 之前一個是init-method 之後。AOP 就是對這些擴充套件點的使用。
注:
BeanFactoryPostProcessor.postProcessBeanFactory()呼叫棧
AbstractApplicationContext.refresh() 方法通過呼叫 invokeBeanFactoryPostProcessors(beanFactory);就是呼叫postProcessBeanFactory() 方法的入口。
AbstractApplicationContext.refresh()方法中呼叫的finishBeanFactoryInitialization(beanFactory) 方法中呼叫了preInstantiateSingletons()方法,確保所有的單例都例項化。所以後面的呼叫順序就是在bean例項化之後初始化bean的時候呼叫了。