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的更多相关文章

  1. spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别

    主要区别就是: BeanFactoryPostProcessor可以修改BEAN的配置信息而BeanPostProcessor不能,下面举个例子说明 BEAN类: package com.spring ...

  2. Spring点滴五:Spring中的后置处理器BeanPostProcessor讲解

    BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...

  3. spring学习四:Spring中的后置处理器BeanPostProcessor

    BeanPostProcessor接口作用: 如果我们想在Spring容器中完成bean实例化.配置以及其他初始化方法前后要添加一些自己逻辑处理.我们需要定义一个或多个BeanPostProcesso ...

  4. Spring 后置处理器【1】

    Spring 后置处理器[1] 简单介绍 一句话:bean 在初始化前或初始化后的瞬间,我自己添加一些业务逻辑 bean 后置处理器类的内容 简单代码 package com.hspedu.sprin ...

  5. Spring的后置处理器BeanPostProcessor

    一.BeanPostProcessor接口的作用 如果我们需要在Spring容器完成Bean的实例化.配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个BeanPostProce ...

  6. spring的后置处理器——BeanPostProcessor以及spring的生命周期

    后置处理器的调用时机 BeanPostProcessor是spring提供的接口,它有两个方法——postProcessBeforeInitialization.postProcessAfterIni ...

  7. Bean后置处理器 BeanPostProcessor

    1.BeanPostProcessor接口的作用 Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理,Bean后置处理器对IOC容器的所有bean实例逐一处理,而非单一实例. 我们可以 ...

  8. Spring 后置处理器 PropertyPlaceholderConfigurer 类(引用外部文件)

    一.PropertyPlaceholderConfigurer类的作用 PropertyPlaceholderConfigurer 是 BeanFactory 后置处理器的实现,也是 BeanFact ...

  9. Spring中的后置处理器BeanPostProcessor讲解

    Spring中提供了很多PostProcessor供开发者进行拓展,例如:BeanPostProcessor.BeanFactoryPostProcessor.BeanValidationPostPr ...

随机推荐

  1. [docker][win10]安装的坑

    右键这个小图标,先signin,注意这里是ID 不是邮箱   image.png 可能starting 时候就报错说 “Containers feature is not enabled” 或者   ...

  2. WPF自定义控件(三)の扩展控件

    扩展控件,顾名思义就是对已有的控件进行扩展,一般继承于已有的原生控件,不排除继承于自定义的控件,不过这样做意义不大,因为既然都自定义了,为什么不一步到位呢,有些不同的需求也可以通过此来完成,不过类似于 ...

  3. 缓存数据库Memcache

    为什么用缓存数据库 MySQL:将数据存储在磁盘上,数据写入读取相对较慢 Memcached:将数据存在内存中的数据库,数据读写都快,但是数据容易丢失 数据存储,数据仓库选择MySQL这种磁盘的数据库 ...

  4. P1101 单词方阵 (单词方阵)

    思路:就是白白的模拟 #include<iostream> using namespace std; ][]; ][]; char kk[] = "yizhong"; ...

  5. 深度学习框架PyTorch一书的学习-第六章-实战指南

    参考:https://github.com/chenyuntc/pytorch-book/tree/v1.0/chapter6-实战指南 希望大家直接到上面的网址去查看代码,下面是本人的笔记 将上面地 ...

  6. go标准库的学习-os

    参考https://studygolang.com/pkgdoc 导入方式: import "os" os包提供了操作系统函数的不依赖平台的接口 一开始简单举个例子: packag ...

  7. Spring Security(九):2.4.4 Checking out the Source(检查来源)

    Since Spring Security is an Open Source project, we’d strongly encourage you to check out the source ...

  8. 从Linux内核角度看中间人攻击(ARP欺骗)并利用Python scapy实现

    邻居子系统与ARP协议 邻居子系统的作用就是将IP地址,转换为MAC地址,类似操作系统中的MMU(内存管理单元),将虚拟地址,转换为物理地址. 其中邻居子系统相当于地址解析协议(IPv4的ARP协议, ...

  9. 工具 docker

    环境配置 软件+环境 虚拟机 资源占用 容器  进程隔离 image(镜像)文件 容器文件 docker hub:仓库 docker container run image_name 挂载: 参考链接 ...

  10. Java多线程(五)——线程等待与唤醒

    一.wait().notify().notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线程进 ...