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. MySQL高级知识(三)——索引

    前言:索引在sql调优部分占据着重要的位置,了解并深入索引对我们来说也是非常重要的.本篇主要介绍MySQL中索引的相关知识点. 1.索引是什么 MySQL官方对索引的定义:索引(Index)是帮助My ...

  2. 在Ubuntu18.04上使用Anaconda

    启动Anaconda Navigator 图形化界面 $ source ~/anaconda3/bin/activate root $ anaconda-navigator 查看目前的conda版本: ...

  3. SpringBoot的简单登陆开发例子

    1:这个例子用spirngboot整合mybatis,jdbc等技术开发的 2:步骤 2.1:新建一个工程 主要的两个步骤已经贴图了,第二张图是直接在pom.xml文件中加入依赖 2.2:新建完项目, ...

  4. Ansible 拷贝文件或目录

    写法如下: [root@localhost ~]$ ansible 192.168.119.134 -m copy -a "src=/etc/passwd dest=/tmp/passwd ...

  5. OpenCV3计算机视觉Python语言实现笔记(二)

    1. 图像与原始字节之间的转换 从概念上讲,一个字节能表示0到255的整数.目前,对于多有的实时图像应用而言,虽然有其他的表示形式,但一个像素通常由每个通道的一个字节表示. 一个OpenCV图像是.a ...

  6. 工具篇-Json处理

    1. @JsonProperty和@SerializedName注解 使用场景 将一个json格式的字符串转换成某个java对象,或者将一个java对象转换成json格式的字符串时,如果json字符串 ...

  7. python:面向对象编程之Zope.interface安装使用

    持续学习python+django中... 一.接口简述 在我们所熟知的面向对象编程语言中,大多提供了接口(interface)的概念.接口在编程语言中指的是一个抽象类型,是抽象方法的集合:它的特点如 ...

  8. phpstorm 免费激活码

    打开网址 http://idea.lanyus.com/ 选择获取注册码,复制生成的验证码 安装完成后,打开软件,依次选择菜单栏 Help -> Register-> Activation ...

  9. macOS下appstore提示未能完成该操作的解决办法

    macOS下App Store下载软件,提示:未能完成该操作.(com.apple.commerce.client 错误 500.) 解决办法: 在终端输入 defaults write com.ap ...

  10. Java 执行远程主机shell命令代码

    pom文件: <dependency> <groupId>org.jvnet.hudson</groupId> <artifactId>ganymed- ...