spring后置处理器BeanPostProcessor
BeanPostProcessor的作用是在调用初始化方法的前后添加一些逻辑,这里初始化方法是指在配置文件中配置init-method,或者实现了InitializingBean接口的afterPropertiesSet方法,注意不包括@PostConstruct这种初始化方式。可以看源码AbstractAutowireCapableBeanFactory类中的invokeInitMethods方法。
1.用法
新建Student类
package com.demo.spring.entity; import javax.annotation.PostConstruct; import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component; /**
* @author chenyk
* @date 2018年5月8日
*/
@Component("student")
public class Student{
private String name;
private int age; private School school; public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
} public void init(){
System.out.println("执行 init方法");
} }
创建实现了BeanPostProcessor接口的后置处理器StudentBeanPostProcessor
package com.demo.spring.entity; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; /**
* Bean后置处理器
* @author chenyk
* @date 2018年6月29日
*/
//以下这两个方法不能返回null,否则在调用初始化方法时会报空指针异常;因为后置处理器从springIOC容器中取出bean实例后需要再把bean实例放回去
public class StudentBeanPostProcessor implements BeanPostProcessor{ /**
* 在bean实例调用初始化方法之前调用
*/
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if(beanName.equals("student")){
System.out.println("开始调用init方法");
}
return bean;
} /**
* 在bean实例调用初始化方法之后调用
*/
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if(beanName.equals("student")){
System.out.println("init方法调用结束");
}
return bean;
}
}
在配置文件aop.xml中添加以下信息
<bean id="student" class="com.demo.spring.entity.Student" init-method="init" >
<property name="name" value="张三"></property>
</bean>
<!-- spring会自动检测实现了BeanPostProcessor接口的类,并将其注册为后置处理器 -->
<bean id="studentBeanPostProcessor" class="com.demo.spring.entity.StudentBeanPostProcessor" />
测试方法
@Test
public void testAop5(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("aop.xml");
}
看下打印信息:
开始调用init方法
2018-07-02 13:58:47,519 DEBUG [AbstractAutowireCapableBeanFactory.java:1731] : Invoking init method 'init' on bean with name 'student' //这一行信息,就是即将调用init-method方法的日志打印
执行 init方法
init方法调用结束
需要注意的是,如果一个类实现了BeanPostProcessor接口,那么这个类就作用于所有的bean实例,我们可以在BeanPostProcessor接口的两个方法中添加自己的控制和逻辑;
2.源码分析
2.1 找到实现BeanPostProcessor接口的类,并将其注册为后置处理器,看源码
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh(); // Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory); try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//发现注册bean后置处理器,在这个方法中进行
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory); // Initialize message source for this context.
initMessageSource(); // Initialize event multicaster for this context.
initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses.
onRefresh(); // Check for listener beans and register them.
registerListeners(); // Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} // Destroy already created singletons to avoid dangling resources.
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // Propagate exception to caller.
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
2.2 后置处理器生效的地方,进入AbstractAutowireCapableBeanFactory类中的initializeBean方法
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
//后置处理器的postProcessBeforeInitialization方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//调用初始化方法有:init-method,实现了InitializingBean接口的方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//后置处理器的postProcessAfterInitialization方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
3.最后,我们看下@PostConstruct执行的时间点。
进入AbstractAutowireCapableBeanFactory类的initializeBean方法
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//这个是后置处理器的方法,其实@PostConstruct是在CommonAnnotationBeanPostProcessor后置处理器的父类InitDestroyAnnotationBeanPostProcessor中实现的,
//也就是说@PostConstruct是由后置处理器来处理实现的,进入该方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
进入applyBeanPostProcessorsBeforeInitialization方法
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException { Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
//在循环中会发现一个类 CommonAnnotationBeanPostProcessor,然后进入其父类InitDestroyAnnotationBeanPostProcessor的postProcessBeforeInitialization该方法 进入该方法
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
进入postProcessBeforeinitialization方法
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//该类封装着一些通过注解的方式标识的初始化方法和销毁方法,以及相关属性
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
//@PostConstrutct注解就是在此处生效调用
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
spring后置处理器BeanPostProcessor的更多相关文章
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
主要区别就是: BeanFactoryPostProcessor可以修改BEAN的配置信息而BeanPostProcessor不能,下面举个例子说明 BEAN类: package com.spring ...
- Spring点滴五:Spring中的后置处理器BeanPostProcessor讲解
BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...
- spring学习四:Spring中的后置处理器BeanPostProcessor
BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...
- Spring 后置处理器【1】
Spring 后置处理器[1] 简单介绍 一句话:bean 在初始化前或初始化后的瞬间,我自己添加一些业务逻辑 bean 后置处理器类的内容 简单代码 package com.hspedu.sprin ...
- Spring的后置处理器BeanPostProcessor
一.BeanPostProcessor接口的作用 如果我们需要在Spring容器完成Bean的实例化.配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProce ...
- spring的后置处理器——BeanPostProcessor以及spring的生命周期
后置处理器的调用时机 BeanPostProcessor是spring提供的接口,它有两个方法——postProcessBeforeInitialization.postProcessAfterIni ...
- Bean后置处理器 BeanPostProcessor
1.BeanPostProcessor接口的作用 Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理,Bean后置处理器对IOC容器的所有bean实例逐一处理,而非单一实例. 我们可以 ...
- Spring 后置处理器 PropertyPlaceholderConfigurer 类(引用外部文件)
一.PropertyPlaceholderConfigurer类的作用 PropertyPlaceholderConfigurer 是 BeanFactory 后置处理器的实现,也是 BeanFact ...
- Spring中的后置处理器BeanPostProcessor讲解
Spring中提供了很多PostProcessor供开发者进行拓展,例如:BeanPostProcessor.BeanFactoryPostProcessor.BeanValidationPostPr ...
随机推荐
- TCP三次握手四次挥手过程详解
http://blog.csdn.net/imilli/article/details/50620104 TCP头部: 其中 ACK SYN 序号 这三个部分在以下会用到,它们的介绍也在下面. ...
- 解决:Vue刷新/载入页面,出现双括号闪现后消失
https://cn.vuejs.org/v2/api/#v-cloak v-cloak 不需要表达式 用法: 这个指令保持在元素上直到关联实例结束编译.和 CSS 规则如 [v-cloak] { d ...
- WPF自定义控件(四)の自定义控件
在实际工作中,WPF提供的控件并不能完全满足不同的设计需求.这时,需要我们设计自定义控件. 这里LZ总结一些自己的思路,特性如下: Coupling UITemplate Behaviour Func ...
- 用python设置定时任务
python中的轻量级定时任务调度库:schedule 提到定时任务调度的时候,相信很多人会想到芹菜celery,要么就写个脚本塞到crontab中.不过,一个小的定时脚本,要用celery的话太 ...
- 如何利用pip自动生成和安装requirements.txt依赖
在查看别人的Python项目时,经常会看到一个requirements.txt文件,里面记录了当前程序的所有依赖包及其精确版本号.这个文件有点类似与Rails的Gemfile.其作用是用来在另一台PC ...
- day12--装饰器
定义(如何理解装饰器):装饰器本生是闭包函数的一种应用,是指在不改变原函数的情况下为原函数添加新的功能的一个函数.它把被装饰的函数作为外层函数的参数传入装饰器,通过闭包操作后返回一个替代版函数. 遵循 ...
- 在Python程序中的进程操作,multiprocess.Process模块
在python程序中的进程操作 之前我们已经了解了很多进程相关的理论知识,了解进程是什么应该不再困难了,刚刚我们已经了解了,运行中的程序就是一个进程.所有的进程都是通过它的父进程来创建的.因此,运行起 ...
- bootstrapvalidator 用法
1.引入js.css 2.用法 API:http://bootstrapvalidator.votintsev.ru/api/ 参考博客:https://blog.csdn.net/u01393846 ...
- 【转】WPF PasswordBox不支持绑定解决方法
原文地址:https://www.cnblogs.com/wxjing67/p/3935717.html PasswordBox的Password属性因为安全原因不支持直接绑定,可以使用依赖属性实现. ...
- 在GridControl控件上绑定图片的几种操作方式
我们知道,基于DevExpress的开发Winform的项目界面的时候,GridControl控件是经常用来绑定数据的,一般以常规的字符内容为主,有时候也会有图片的显示需要,那么如果显示图片,我们应该 ...