1.概述

转载:Spring中BeanPostProcessor

对文章:SpringBoot : 定制化Bean的利器:BeanPostProcessor & BeanFactoryPostProcessor 的一个补充。

测试所使用的Spring版本:4.3.12.RELEASE

一、bean的生命周期:创建—>初始化—>销毁

容器管理 bean 的生命周期,我们可以自定义初始化和销毁方法,容器在 bean 进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。

1、bean的创建:

单实例:在容器启动时创建对象;
多实例:在每次获取时创建对象。

2、bean的初始化:

单实例:对象创建完成,并赋值好,调用初始化方法
多实例:获取对象时,创建对象,赋值,然后调用初始化方法

3、bean的销毁:

单实例:容器关闭时销毁
多实例:容器不会管理这个bean,容器不会调用销毁方法。

二、插手初始化/销毁过程的四种操作方式:

1、指定初始化和销毁方法:通过 @Bean 注解指定 init-method 和 destroy-method

第一步:实体类

@Component
public class Car {public Car() {System.out.println("car constructor...");}public void init() {System.out.println("car ... init...");}public void detory() {System.out.println("car ... detory...");}}

第二步:配置

@Configuration
public class MainConfigOfLifeCycle {//@Scope("prototype")   //多实例@Bean(initMethod="init",destroyMethod="detory")public Car car(){return new Car();}}

第三步:测试

public class IOCTest_LifeCycle {@Testpublic void test01(){//创建 IOC 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);System.out.println("容器创建完成...");//applicationContext.getBean("car");  //多实例测试用//关闭容器applicationContext.close();}}

第四步:结果

六月 03, 2019 2:28:08 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2db0f6b2: startup date [Mon Jun 03 14:28:08 CST 2019]; root of context hierarchy
六月 03, 2019 2:28:09 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
car constructor...
car ... init...
容器创建完成...
六月 03, 2019 2:28:09 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2db0f6b2: startup date [Mon Jun 03 14:28:08 CST 2019]; root of context hierarchy
car ... detory...

由上可看出,对于单实例的 bean,容器创建时执行了构造方法和初始化方法,容器创建完成后可直接使用;容器关闭时执行销毁方法。而对于多实例来说,容器创建时不会执行bean的构造方法和初始化方法,只有在使用到bean的时候,才会去执行构造方法和初始化方法,容器关闭时,也不会执行销毁方法。(这里就不贴结果了,有兴趣自己测试就行)

2、通过让 Bean 实现 InitializingBean (定义初始化逻辑),DisposableBean(定义销毁逻辑)

第一步:实体类

@Component
public class Cat implements InitializingBean,DisposableBean {public Cat(){System.out.println("cat constructor...");}public void destroy() throws Exception {System.out.println("cat...destroy...");}public void afterPropertiesSet() throws Exception {System.out.println("cat...afterPropertiesSet...");     }
}

第二步:配置

@Configuration
public class MainConfigOfLifeCycle {@Beanpublic Cat cat(){return new Cat();}
}

第三步:测试

public class IOCTest_LifeCycle {@Testpublic void test01(){//创建 IOC 容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);System.out.println("容器创建完成...");//applicationContext.getBean("cat");  //多实例测试用//关闭容器applicationContext.close();}}

结果跟之前的是一样的,不再多说了。

3、使用 JSR250:@PostConstruct、@PreDestroy

  • @PostConstruct:在 bean 创建完成并且属性赋值完成后执行初始化方法;
  • @PreDestroy:在容器销毁 bean 之前通知我们进行清理工作。

实体类如下,其他的操作和上面相同。

@Component
public class Dog {public Dog(){System.out.println("dog constructor...");}@PostConstructpublic void init(){System.out.println("Dog....@PostConstruct...");}@PreDestroypublic void detory(){System.out.println("Dog....@PreDestroy...");}}

4、BeanPostProcessor【interface】:bean 的后置处理器

在 bean 初始化前后进行一些处理工作:

  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterIntialization:在初始化之后工作
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);return bean;}public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);return bean;}}@Configuration
public class MainConfigOfLifeCycle {//@Scope("prototype")   //多实例@Beanpublic Dog dog(){return new Dog();}@Beanpublic MyBeanPostProcessor myBeanPostProcessor(){return new MyBeanPostProcessor();}
}

结果:

//省略
dog constructor...            //构造方法
postProcessBeforeInitialization...dog=>com.wyq.bean.Dog@1e67a849    //初始化之前
Dog....@PostConstruct...         //初始化
postProcessAfterInitialization...dog=>com.wyq.bean.Dog@1e67a849     //初始化之后
容器创建完成...
六月 03, 2019 3:32:25 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2db0f6b2: startup date [Mon Jun 03 15:32:24 CST 2019]; root of context hierarchy
Dog....@PreDestroy...

三、BeanPostProcessor原理

1、作用:在 bean 初始化前后进行其他操作。

BeanPostProcessor.postProcessBeforeInitialization
初始化...
BeanPostProcessor.postProcessAfterInitialization

2、初始化之前/之后具体是什么时间?

断点调试,慢慢看:

(1)首先是创建 IOC 容器:new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class)

(2)紧接着是执行构造方法:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {this();this.register(annotatedClasses);this.refresh();
}

这里调用了 refresh() 方法,刷新容器。

(3)看一下 refresh() 方法

public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);//注意this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}}

(4)refresh 中 调用了 finishBeanFactoryInitialization(beanFactory)

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {//省略beanFactory.preInstantiateSingletons();
}

(5)finishBeanFactoryInitialization 中调用 preInstantiateSingletons

public void preInstantiateSingletons() throws BeansException {//......if (this.isFactoryBean(beanName)) {//省略...} else {this.getBean(beanName);}}}}

(6)preInstantiateSingletons 调用 getBean,getBean 又调用 getSingleton

    public Object getBean(String name) throws BeansException {return this.doGetBean(name, (Class)null, (Object[])null, false);}protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {//......if (sharedInstance != null && args == null) {//......} else {//......try {//......if (mbd.isSingleton()) {sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {public Object getObject() throws BeansException {try {return AbstractBeanFactory.this.createBean(beanName, mbd, args);} catch (BeansException var2) {AbstractBeanFactory.this.destroySingleton(beanName);throw var2;}}});bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);} else if (mbd.isPrototype()) {//......} else {//......}} catch (BeansException var23) {//......}}//......}

(7)getSingleton 中调用 getObject,由于是第一次,容器中并没有 bean,所以调用 createBean 创建 bean

    protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {//......Object beanInstance;//......beanInstance = this.doCreateBean(beanName, mbdToUse, args);if (this.logger.isDebugEnabled()) {this.logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}

(8)如何创建 bean,看一下 doCreateBean 方法,调用 initializeBean 初始化了 bean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) throws BeanCreationException {//......Object exposedObject = bean;try {//这个也要注意,后面要说this.populateBean(beanName, mbd, instanceWrapper);if (exposedObject != null) {//初始化beanexposedObject = this.initializeBean(beanName, exposedObject, mbd);}} catch (Throwable var18) {//......}//......try {this.registerDisposableBeanIfNecessary(beanName, bean, mbd);return exposedObject;} catch (BeanDefinitionValidationException var16) {//......}}

(9)initializeBean 中调用了后置处理器 BeanPostProcessor

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {//......Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//这里调用后置处理器wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);}try {//执行初始化方法this.invokeInitMethods(beanName, wrappedBean, mbd);} catch (Throwable var6) {throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);}if (mbd == null || !mbd.isSynthetic()) {//调用后置处理器wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}//......return wrappedBean;}public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {Object result = existingBean;Iterator var4 = this.getBeanPostProcessors().iterator();/*遍历得到容器中所有的BeanPostProcessor,挨个执行beforeInitailization一旦返回null,跳出for循环,不会执行后面的BeanPostProcessor*/do {if (!var4.hasNext()) {return result;}BeanPostProcessor beanProcessor = (BeanPostProcessor)var4.next();result = beanProcessor.postProcessBeforeInitialization(result, beanName);} while(result != null);return result;}

(10)这里回看一下(8)调用 initializeBean 之前还调用了 populateBean,这个就是给 bean 的所有属性进行赋值

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {PropertyValues pvs = mbd.getPropertyValues();if (bw == null) {if (!((PropertyValues)pvs).isEmpty()) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");}} else {boolean continueWithPropertyPopulation = true;if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {Iterator var6 = this.getBeanPostProcessors().iterator();while(var6.hasNext()) {BeanPostProcessor bp = (BeanPostProcessor)var6.next();if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {continueWithPropertyPopulation = false;break;}}}}if (continueWithPropertyPopulation) {if (mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);if (mbd.getResolvedAutowireMode() == 1) {this.autowireByName(beanName, mbd, bw, newPvs);}if (mbd.getResolvedAutowireMode() == 2) {this.autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = mbd.getDependencyCheck() != 0;if (hasInstAwareBpps || needsDepCheck) {PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);if (hasInstAwareBpps) {Iterator var9 = this.getBeanPostProcessors().iterator();while(var9.hasNext()) {BeanPostProcessor bp = (BeanPostProcessor)var9.next();if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;pvs = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvs == null) {return;}}}}if (needsDepCheck) {this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);}}this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);}}}

3、总结:BeanPostProcessor原理

populateBean(beanName, mbd, instanceWrapper);//给bean属性赋值
initializeBean
{applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);invokeInitMethods(beanName, wrappedBean, mbd);//执行初始化方法applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

【Spring】Spring中BeanPostProcessor相关推荐

  1. Spring配置中context:annotation-config VS context:component-scan

    Spring 中在使用注解(Annotation)会涉及到< context:annotation-config> 和 < context:component-scan>配置, ...

  2. 【面试题】Spring框架中Bean的生命周期

    生命周期 1.实例化一个Bean--也就是我们常说的new一个对象: 2.按照Spring上下文对实例化的Bean进行配置--也就是IOC注入: 3.如果这个Bean已经实现了BeanNameAwar ...

  3. Spring框架中bean的生命周期

    ean在Spring容器中从创建到销毁经历了若干阶段,每一阶段都可以针对Spring如何管理bean进行个性化定制. 正如你所见,在bean准备就绪之前,bean工厂执行了若干启动步骤. 我们对上图进 ...

  4. 再见面试官:你能说说 Spring 框架中 Bean 的生命周期吗?

    首先简单说一下(以下为一个回答的参考模板) 1.实例化一个Bean--也就是我们常说的new: 2.按照Spring上下文对实例化的Bean进行配置--也就是IOC注入: 3.如果这个Bean已经实现 ...

  5. Spring BPP中优雅的创建动态代理Bean

    Spring BPP中优雅的创建动态代理Bean 一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出C ...

  6. java spring框架 注解_详解Java的Spring框架中的注解的用法

    1. 使用Spring注解来注入属性 1.1. 使用注解以前我们是怎样注入属性的类的实现: class UserManagerImpl implements UserManager { private ...

  7. Spring系列之BeanPostProcessor分析

    在Spring系列之Bean的生命周期及相关源码中,我们最后简单使用过BeanPostProcessor,这次我们就结合源码来具体谈谈这个BeanPostProcessor的作用. 实现BeanPos ...

  8. 【小家Spring】注意BeanPostProcessor启动时对依赖Bean的“误伤”陷阱(is not eligible for getting processed by all...)

    每篇一句 祝大家五一国际劳动节快乐~你是在快乐的撸码,还是在快乐的浪呢? 本文已被https://yourbatman.cn收录:程序员专用网盘https://wangpan.yourbatman.c ...

  9. Spring容器中的Bean是否会被GC呢?

    Spring容器中的Bean是否会被GC呢?最近好几次被校招实习生问及,对于初学者来说,这应该是一个有意思的问题,鉴于此,笔者顺便写个这个文档. 1.Spring容器中Bean的作用域 当通过Spri ...

最新文章

  1. Codeforces Round #701 (Div. 2) A ~ F ,6题全,超高质量良心题解【每日亿题】2021/2/13
  2. java程序向mysql插入中文变问号
  3. windows mklink创建软连接命令使用示例
  4. 三维家可以导入别人的方案吗_广州深圳天津形位公差检测三维缺陷检测服务
  5. import java.io用什么写_问问各位大佬,使用了fiilewrite,为什么写入不到文件
  6. Java到底如何更优雅的处理空值?
  7. 性能调试工具——oprofile
  8. ug10万能许可证一键安装_优胜UG4.0-UG12.0-许可证一键自动安装下载|
  9. 【sketchup 2021】草图大师的场景优化工具1【群组工具和组件工具的详细用法(重要)】
  10. @inherited 注解详解
  11. 计算机有哪些交叉专业研究生,与理工科交叉的计算机专业考研方向有哪些?
  12. uniapp 公众号微信支付提示 调用支付jsapi缺少参数appid
  13. 陶瓷纤维毯行业调研报告 - 市场现状分析与发展前景预测
  14. 二维高斯曲面拟合法求取光斑中心
  15. ContentObserver去实现拒收短信或短信黑名单等功能
  16. Unity任意轴向朝向某目标实现LookAt功能
  17. 2.4 一阶隐式微分方程与参数表示
  18. Beethoven, Mozart, Chopin on my iPhone 4S
  19. 中芯国际透露:14nm或不能为某客户代工
  20. CAS:1347750-20-2,氨基PEG巯基,NH2-PEG-SH,Amine-PEG-Thiol

热门文章

  1. 李佳琦“云逛”进博会 携手央视带货阿富汗松子
  2. 男子刷机多次拒绝来电 维修师傅的做法被网友怒赞
  3. 华为车规芯片麒麟990A架构曝光
  4. 10月份全球最畅销电动汽车:Model 3第一 五菱宏光MiniEV第二
  5. 那是财务自由的声音!寒武纪上市造就一批85后亿万富翁
  6. iPhone 12延期恐实锤:台积电5nm A14芯片将延期3个月
  7. 苹果宣布对2019款iPad降价:最高降幅达500元
  8. 华为再获90天“临时许可证” 可继续维护客户
  9. 抖音回应李小璐PGone视频曝光:草稿视频不会上传到后台
  10. 三星Galaxy Note10系列国内发布会官宣:8月21日见!