【Spring】Spring中BeanPostProcessor
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相关推荐
- Spring配置中context:annotation-config VS context:component-scan
Spring 中在使用注解(Annotation)会涉及到< context:annotation-config> 和 < context:component-scan>配置, ...
- 【面试题】Spring框架中Bean的生命周期
生命周期 1.实例化一个Bean--也就是我们常说的new一个对象: 2.按照Spring上下文对实例化的Bean进行配置--也就是IOC注入: 3.如果这个Bean已经实现了BeanNameAwar ...
- Spring框架中bean的生命周期
ean在Spring容器中从创建到销毁经历了若干阶段,每一阶段都可以针对Spring如何管理bean进行个性化定制. 正如你所见,在bean准备就绪之前,bean工厂执行了若干启动步骤. 我们对上图进 ...
- 再见面试官:你能说说 Spring 框架中 Bean 的生命周期吗?
首先简单说一下(以下为一个回答的参考模板) 1.实例化一个Bean--也就是我们常说的new: 2.按照Spring上下文对实例化的Bean进行配置--也就是IOC注入: 3.如果这个Bean已经实现 ...
- Spring BPP中优雅的创建动态代理Bean
Spring BPP中优雅的创建动态代理Bean 一.前言 本文章所讲并没有基于Aspectj,而是直接通过Cglib以及ProxyFactoryBean去创建代理Bean.通过下面的例子,可以看出C ...
- java spring框架 注解_详解Java的Spring框架中的注解的用法
1. 使用Spring注解来注入属性 1.1. 使用注解以前我们是怎样注入属性的类的实现: class UserManagerImpl implements UserManager { private ...
- Spring系列之BeanPostProcessor分析
在Spring系列之Bean的生命周期及相关源码中,我们最后简单使用过BeanPostProcessor,这次我们就结合源码来具体谈谈这个BeanPostProcessor的作用. 实现BeanPos ...
- 【小家Spring】注意BeanPostProcessor启动时对依赖Bean的“误伤”陷阱(is not eligible for getting processed by all...)
每篇一句 祝大家五一国际劳动节快乐~你是在快乐的撸码,还是在快乐的浪呢? 本文已被https://yourbatman.cn收录:程序员专用网盘https://wangpan.yourbatman.c ...
- Spring容器中的Bean是否会被GC呢?
Spring容器中的Bean是否会被GC呢?最近好几次被校招实习生问及,对于初学者来说,这应该是一个有意思的问题,鉴于此,笔者顺便写个这个文档. 1.Spring容器中Bean的作用域 当通过Spri ...
最新文章
- Codeforces Round #701 (Div. 2) A ~ F ,6题全,超高质量良心题解【每日亿题】2021/2/13
- java程序向mysql插入中文变问号
- windows mklink创建软连接命令使用示例
- 三维家可以导入别人的方案吗_广州深圳天津形位公差检测三维缺陷检测服务
- import java.io用什么写_问问各位大佬,使用了fiilewrite,为什么写入不到文件
- Java到底如何更优雅的处理空值?
- 性能调试工具——oprofile
- ug10万能许可证一键安装_优胜UG4.0-UG12.0-许可证一键自动安装下载|
- 【sketchup 2021】草图大师的场景优化工具1【群组工具和组件工具的详细用法(重要)】
- @inherited 注解详解
- 计算机有哪些交叉专业研究生,与理工科交叉的计算机专业考研方向有哪些?
- uniapp 公众号微信支付提示 调用支付jsapi缺少参数appid
- 陶瓷纤维毯行业调研报告 - 市场现状分析与发展前景预测
- 二维高斯曲面拟合法求取光斑中心
- ContentObserver去实现拒收短信或短信黑名单等功能
- Unity任意轴向朝向某目标实现LookAt功能
- 2.4 一阶隐式微分方程与参数表示
- Beethoven, Mozart, Chopin on my iPhone 4S
- 中芯国际透露:14nm或不能为某客户代工
- CAS:1347750-20-2,氨基PEG巯基,NH2-PEG-SH,Amine-PEG-Thiol
热门文章
- 李佳琦“云逛”进博会 携手央视带货阿富汗松子
- 男子刷机多次拒绝来电 维修师傅的做法被网友怒赞
- 华为车规芯片麒麟990A架构曝光
- 10月份全球最畅销电动汽车:Model 3第一 五菱宏光MiniEV第二
- 那是财务自由的声音!寒武纪上市造就一批85后亿万富翁
- iPhone 12延期恐实锤:台积电5nm A14芯片将延期3个月
- 苹果宣布对2019款iPad降价:最高降幅达500元
- 华为再获90天“临时许可证” 可继续维护客户
- 抖音回应李小璐PGone视频曝光:草稿视频不会上传到后台
- 三星Galaxy Note10系列国内发布会官宣:8月21日见!