Spring中的後置處理器BeanPostProcessor講解

BeanPostProcessor接口作用:

如果我們想在Spring容器中完成bean實例化、配置以及其他初始化方法前後要添加一些自己邏輯處理。我們需要定義一個或多個BeanPostProcessor接口實現類,然後註冊到Spring IoC容器中。

package com.test.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* bean後置處理器
* @author zss
*
*/
public class PostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
if ("narCodeService".equals(beanName)) {//過濾掉bean實例ID為narCodeService
return bean;
}
System.out.println("後置處理器處理bean=【"+beanName+"】開始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
if ("narCodeService".equals(beanName)) {
return bean;
}
System.out.println("後置處理器處理bean=【"+beanName+"】完畢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
}

注意:接口中兩個方法不能返回null,如果返回null那麼在後續初始化方法將報空指針異常或者通過getBean()方法獲取不到bena實例對象,因為後置處理器從Spring IoC容器中取出bean實例對象沒有再次放回IoC容器中!

將Spring的後置處理器PostProcessor配置到Spring配置文件中


<beans> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean>
/<bean>
<bean>
<property>
<property>
/<bean>

<bean>
/<beans>

BeanPostProcessor API:

public interface BeanPostProcessor { 

//實例化、依賴注入完畢,在調用顯示的初始化之前完成一些定製的初始化任務
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;


//實例化、依賴注入、初始化完畢時執行
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

}
由API可以看出:
1:後置處理器的postProcessorBeforeInitailization方法是在bean實例化,依賴注入之後及自定義初始化方法(例如:配置文件中bean標籤添加init-method屬性指定Java類中初始化方法、
@PostConstruct註解指定初始化方法,Java類實現InitailztingBean接口)之前調用

2:後置處理器的postProcessorAfterInitailization方法是在bean實例化、依賴注入及自定義初始化方法之後調用
注意:
1.BeanFactory和ApplicationContext兩個容器對待bean的後置處理器稍微有些不同。ApplicationContext容器會自動檢測Spring配置文件中那些bean所對應的Java類實現了BeanPostProcessor
接口,並自動把它們註冊為後置處理器。在創建bean過程中調用它們,所以部署一個後置處理器跟普通的bean沒有什麼太大區別。

2.BeanFactory容器註冊bean後置處理器時必須通過代碼顯示的註冊,在IoC容器繼承體系中的ConfigurableBeanFactory接口中定義了註冊方法

 void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

Spring如何調用多個BeanPostProcessor實現類:

我們可以在Spring配置文件中添加多個BeanPostProcessor(後置處理器)接口實現類,在默認情況下Spring容器會根據後置處理器的定義順序來依次調用。

Spring配置文件:


<beans> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean>
/<bean>

<bean>
<bean>
/<beans>

BeanPostProcessor實現類:

package com.test.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* bean後置處理器
* @author zss
*
*/
public class PostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("後置處理器處理bean=【"+beanName+"】開始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("後置處理器處理bean=【"+beanName+"】完畢!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
}
----------------------------------------------------------------------------------------------------------------------------------------
package com.test.spring;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class PostProcessorB implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("後置處理器開始調用了");

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean,
String beanName) throws BeansException {
System.out.println("後置處理器調用結束了");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return bean;
}
}

Test case:

package com.test.spring;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class T {
AbstractApplicationContext applicationcontext=null;
@Before
public void before() {
System.out.println("》》》Spring ApplicationContext容器開始初始化了......");
applicationcontext= new ClassPathXmlApplicationContext(new String[]{"test1-service.xml"});
System.out.println("》》》Spring ApplicationContext容器初始化完畢了......");
}
@Test
public void test() {
applicationcontext.registerShutdownHook();
}
}

測試結果:

》》》Spring ApplicationContext容器開始初始化了...... 

2017-03-19 10:50:29 INFO:ClassPathXmlApplicationContext-Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@18c92ff9: startup date [Sun Mar 19 10:50:29 CST 2017]; root of context hierarchy
2017-03-19 10:50:29 INFO:XmlBeanDefinitionReader-Loading XML bean definitions from class path resource [test1-service.xml]
後置處理器處理bean=【narCodeService】開始
後置處理器開始調用了
後置處理器處理bean=【narCodeService】完畢!
後置處理器調用結束了
》》》Spring ApplicationContext容器初始化完畢了......
2017-03-19 10:50:34 INFO:ClassPathXmlApplicationContext-Closing org.springframework.context.support.ClassPathXmlApplicationContext@18c92ff9: startup date [Sun Mar 19 10:50:29 CST 2017]; root of context hierarchy

在Spring機制中可以指定後置處理器調用順序,通過讓BeanPostProcessor接口實現類實現Ordered接口getOrder方法,該方法返回一整數,默認值為 0,優先級最高,值越大優先級越低。

最後

感謝大家的耐心閱讀,喜歡文章的可以關注我,持續為大家推送更多技術乾貨,資料,面試題~

需要面試題和架構資料的可以私信【面試題】或【架構】可獲取Java架構資源合集以及600道面試題+答案。

最後祝福所有遇到瓶疾且不知道怎麼辦的Java程序員們,在往後的工作與面試中一切順利。


分享到:


相關文章: