-
1 # 列克美食
-
2 # 程式猿W
其實無論是前置和後置,還是其他介面,都是Spring 可擴充套件性表現。下面將會說明 Spring的前置和後置處理器,以及在 Spring 原始碼裡執行的時機。最後說明 Spring 其他介面的 說明
下面將從以下幾個方面進行說明:
前置處理器和後置處理器
Spring 的生命週期
Spring 生命週期所涉及的原始碼
Spring 其他可擴充套件介面
前置處理器和後置處理器Spring 的後置處理器主要為 BeanFactoryPostProcessor 和 BeanPostProcessor
1、BeanFactoryPostProcessor
BeanFactoryPostProcessor 是針對BeanDefinition 級別的後置處理器,它可以修改Bean的 定義,呼叫該介面時,bean還沒有進行初始化,它只有一個方法如下:
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
① 怎樣自定義BeanFactoryPostProcessor?
透過實現BeanFactoryPostProcessor 介面方法,來修改yjLog bean的載入方式。
② 使用場景有哪些 ?
比如我們配置資料庫資訊時,經常使用佔位符${username},那麼 Spring在什麼時候進行值的替換呢?
當BeanFactory 在 第一階段載入 完成配置資訊時,儲存的物件屬性資訊還是以佔位符的形式 存在,這個解析的工作是在 PropertySourcesPlaceholderConfigurer 中進行解析的。
從下面類圖看:
PropertySourcesPlaceholderConfigurer 實現了 BeanFactoryPostProcessor 的介面
在下面的方法執行的替換:
呼叫鏈如下:
Spring 初始化的主要步驟如下:
BeanFactoryPostProcessor 的 呼叫是在下面方法中
// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);
執行堆疊如下:
我們驗證一下:BeanFactoryPostProcessor 實在 BeanDefinition 都載入完成才呼叫的
執行上述方法前:Beanfactory裡的BeanDefiniton定義如下:
2、BeanFactoryPostProcessor
BeanFactoryPostProcessor 是針對getBean操作獲得的 對的後置處理器 。他有兩個方法,一個在Bean初始化前執行,一個在初始化後執行
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean;}
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean;}
① 怎樣自定義 BeanFactoryPostProcessor
② 在原始碼的執行位置
執行堆疊如下:
呼叫步驟如下:
// 1.呼叫類的構造方法
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object exposedObject = bean;
try {
//2.給屬性賦值
populateBean(beanName, mbd, instanceWrapper);
//3.初始化bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
1.呼叫類的構造 方法
2.給屬性賦值
3. 初始化
(1) 給 *Aware 介面複製
(2) 執行 BeanPostProcessor postProcessBeforeInitialization
(3) 執行 InitializingBean 介面方法,執行 自定義的init-mathod
(4) 執行 BeanPostProcessor postProcessAfterInitialization 方法
3、BeanDefinitionRegistryPostProcessor
執行時機:所有的bean定義資訊將要被載入到容器中,Bean例項還沒有被初始化。
BeanDefinitionRegistryPostProcessor 介面可以看作是BeanFactoryPostProcessor和ImportBeanDefinitionRegistrar的功能集合
既可以獲取和修改BeanDefinition的元資料,也可以實現BeanDefinition的註冊、移除等操作。
怎樣自定義一個 BeanFactoryPostProcessor
驗證 執行時機:
此時registry 已經以Bean的 定義資訊
spring 生命週期如下圖執行步驟如下:
1、執行建構函式
2、給屬性賦值
3、給呼叫*aware介面
4、執行BeanPostProcessor前置方法
5、呼叫InitializingBean的介面afterPropertiesSet方法
6、呼叫自定義的init方法
@Component
public class Book {
public Book() {
System.out.println("book 的構造方法");
}
@PostConstruct
public void init() {
System.out.println("book 的PostConstruct標誌的方法");
}
@PreDestroy
public void destory() {
System.out.println("book 的PreDestory標註的方法");
}
}
7、執行BeanPostProcessor後置方法
8、呼叫 DisposableBean destroy 銷燬
9、呼叫自定義的銷燬方法
@PreDestroy
public void destory() {
System.out.println("book 的PreDestory標註的方法");
}
Spring 生命週期所涉及的原始碼主要的程式碼如下:
① instanceWrapper = createBeanInstance(beanName, mbd, args);
呼叫構造方法
② populateBean(beanName, mbd, instanceWrapper)
給屬性賦值
(1) invokeAwareMethods(beanName, bean);
執行* Aware 介面
(2) BeanPostProcessor 前置方法
(3) invokeInitMethods
呼叫InitializingBean的介面afterPropertiesSet方法 或者自定義的init方法
④ 呼叫 BeanPostProcessor 後置方法
Spring 其他可擴充套件介面1、ImportBeanDefinitionRegistrar介面
2、FactoryBean介面
3、ApplicationListener
--------------------------
回覆列表
Spirng中BeanPostProcessor和InstantiationAwareBeanPostProcessorAdapter兩個介面都可以實現對bean前置後置處理的效果,那這次先講解一下BeanPostProcessor處理器的使用
先看一下BeanPostProcessor介面的原始碼,它定義了兩個方法,一個在bean初始化之前,一個在bean初始化之後
public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }}下面,我們來實現這個類,測試一下Spring中的前置後置處理器吧
首先是pom.xml,增加Spring相關的依賴
定義介面實現類:
public class ISomeService implements BaseService { public String doSomething() { // 增強效果:返回內容全部大寫 return "Hello i am kxm"; } public String eat() { return "eat food"; }}實現BeanPostProcessor介面
public class MyBeanPostProcessor implements BeanPostProcessor { // 前置處理器 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { Class beanClass = bean.getClass(); if (beanClass == ISomeService.class) { System.out.println("bean 物件初始化之前······"); } return bean; }// 後置處理器 --- 此處具體的實現用的是Java中的動態代理
public Object postProcessAfterInitialization(final Object beanInstance, String beanName) throws BeansException { // 為當前 bean 物件註冊監控代理物件,負責增強 bean 物件方法的能力 Class beanClass = beanInstance.getClass(); if (beanClass == ISomeService.class) { Object proxy = Proxy.newProxyInstance(beanInstance.getClass().getClassLoader(),beanInstance.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("ISomeService 中的 doSome() 被攔截了···"); String result = (String) method.invoke(beanInstance, args); return result.toUpperCase(); } }); return proxy; } return beanInstance; }}Spring的配置檔案如下:
<bean></bean>測試類如下:
public class TestBeanPostProcessor { public static void main(String[] args) { /** * BeanPostProcessor 前置後置處理器 */ ApplicationContext factory = new ClassPathXmlApplicationContext("spring_config.xml"); BaseService serviceObj = (BaseService) factory.getBean("iSomeService"); System.out.println(serviceObj.doSomething()); }}測試結果截圖:
可以觀察到,我們明明在程式碼中對於doSomething方法定義的是小寫,但是通過後置處理器,攔截了原本的方法,而是透過動態代理的方式把方法的結果進行了一定程度的改變,這就是Spring中的前置後置處理器----BeanPostProcessor