BeanPostProcessor:後置處理器
spring使用模板模式,在bean的創建過程中安插了許多錨點,用戶尋找對應的錨點,通過重寫方法介入到bean的創建過程當中。本節通過重寫這些錨點,學習如何使用BeanPostProcessor、獲取各類BeanAware並且理清bean的生命週期
代碼
控制檯
// 控制檯的輸出結果
1. postProcessBeforeInstantiation被調用
2. 構造方法被調用,name:小小
3. postProcessAfterInstantiation被調用
4. postProcessProperties被調用
5. BeanNameAware被調用, 獲取到的beanName:lifeCycleBean
6. BeanFactoryAware被調用,獲取到beanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory@117e949d: defining beans [lifeCycleBean,lifeCycleBeanPostProcessor]; root of factory hierarchy
7. ApplicationContextAware被調用,獲取到ApplicationContextAware:org.springframework.context.support.ClassPathXmlApplicationContext@71e9ddb4, started on Sat Feb 22 20:30:35 CST 2020
8. postProcessBeforeInitialization被調用,把name改成中中
9. afterPropertiesSet被調用
10. myInit自定義初始化方法被調用,name:中中
11. postProcessAfterInitialization被調用,把name改成大大
12. bean創建完成 name: 大大
13. DisposableBean被調用
14. destroy-method自定義銷燬方法被調用
Process finished with exit code 0
創建類LifeCycleBean
public class LifeCycleBean implements
BeanNameAware,
BeanFactoryAware,
ApplicationContextAware,
InitializingBean,
DisposableBean {
private BeanFactory beanFactory;
private ApplicationContext applicationContext;
private String name;
public LifeCycleBean(String name) {
System.out.println("2. 構造方法被調用,name:" + name);
this.name = name;
}
@Override
public void setBeanName(String name) {
System.out.println("5. BeanNameAware被調用, 獲取到的beanName:" + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("6. BeanFactoryAware被調用,獲取到beanFactory:" + beanFactory);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("7. ApplicationContextAware被調用,獲取到ApplicationContextAware:" + applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("9. afterPropertiesSet被調用");
}
public void myInit() {
System.out.println("10. myInit自定義初始化方法被調用,name:" + getName());
}
@Override
public void destroy() throws Exception {
System.out.println("13. DisposableBean被調用");
}
public void myDestroy() {
System.out.println("14. destroy-method自定義銷燬方法被調用");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BeanFactory getBeanFactory() {
return beanFactory;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
}
創建BeanPostProcessor後置處理器(postProcessProperties過時了,這裏就不演示了)
public class LifeCycleBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.out.println("1. postProcessBeforeInstantiation被調用");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.out.println("3. postProcessAfterInstantiation被調用");
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
System.out.println("4. postProcessProperties被調用");
}
return null;
}
// @Override
// public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
// return pvs;
// }
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
((LifeCycleBean) bean).setName("中中");
System.out.println("8. postProcessBeforeInitialization被調用,把name改成中中");
}鄭州婦科醫院 http://www.120zzkd.com/
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName.equals("lifeCycleBean")) {
((LifeCycleBean) bean).setName("大大");
System.out.println("11. postProcessAfterInitialization被調用,把name改成大大");
}
return bean;
}
}
xml配置文件
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
destroy-method="myDestroy"
init-method="myInit">
測試類
/**
* @author: chaitou
*/
public class LifeCycleTest {
@Test
public void test() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("lifeCycle.xml");
LifeCycleBean myLifeCycleBean = applicationContext.getBean("lifeCycleBean", LifeCycleBean.class);
System.out.println("12. bean創建完成 name: " + myLifeCycleBean.getName());
((ClassPathXmlApplicationContext) applicationContext).destroy();
}
}
結果
// 控制檯的輸出結果
1. postProcessBeforeInstantiation被調用
2. 構造方法被調用,name:小小
3. postProcessAfterInstantiation被調用
4. postProcessProperties被調用
5. BeanNameAware被調用, 獲取到的beanName:lifeCycleBean
6. BeanFactoryAware被調用,獲取到beanFactory:org.springframework.beans.factory.support.DefaultListableBeanFactory@117e949d: defining beans [lifeCycleBean,lifeCycleBeanPostProcessor]; root of factory hierarchy
7. ApplicationContextAware被調用,獲取到ApplicationContextAware:org.springframework.context.support.ClassPathXmlApplicationContext@71e9ddb4, started on Sat Feb 22 20:30:35 CST 2020
8. postProcessBeforeInitialization被調用,把name改成中中
9. afterPropertiesSet被調用
10. myInit自定義初始化方法被調用,name:中中
11. postProcessAfterInitialization被調用,把name改成大大
12. bean創建完成 name: 大大
13. DisposableBean被調用
14. destroy-method自定義銷燬方法被調用
Process finished with exit code 0
分析總結
BeanPostProcess
實例化相關:postProcessBeforeInstantiation、postProcessAfterInstantiation
填充屬性相關:postProcessProperties、postProcessPropertyValues(已過時沒有演示)
初始化相關:postProcessBeforeInitialization、postProcessAfterInitialization
通過重寫BeanPostProcess的方法,可以介入bean創建的不同環節。同時通過postProcessBeforeInitialization將bean的name屬性值從小小改成了中中,又通過postProcessAfterInitialization將中中改成了大大,成功介入了bean的創建,並且依據我們的意願修改了bean
BeanNameAware、BeanFactoryAware、ApplicationContextAware
這3類不屬於後置處理器的範疇,學名叫感知器,讓bean能感知到整個容器上下文信息的接口。spring在創建過程中,通過回調子類的setBeanName, setBeanFactory, setApplicationContext實現了BeanName, BeanFactory, ApplicationContext的注入,讓bean能夠感知獲取到spring上下文的相關信息。雖然實現的東西很牛逼,但是實現的原理一點不復雜。通過檢測當前的bean是否實現相關Aware,如果實現則調用子類set方法,將當前的BeanFactory等作爲參數傳入,直接上源碼,看不懂可以參考這篇源碼:(https://blog.csdn.net/chaitoudaren/article/details/104833613)
spring源碼17: 初始化
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}