一、BeanFactoryPostProcessor和BeanPostProcessor的区别

BeanFactoryPostProcessor和BeanPostProcessor都是spring初始化bean的扩展点。两个接口非常相似。

BeanFactoryPostProcessor可以对bean的定义(配置元数据)进行处理。也就是说,Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。如果你愿意,你可以配置多个BeanFactoryPostProcessor。你还能通过设置'order'属性来控制BeanFactoryPostProcessor的执行次序。

注册BeanFactoryPostProcessor的实例,需要重载void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

通过beanFactory可以获取bean的示例或定义等。同时可以修改bean的属性,这是和BeanPostProcessor最大的区别。

例如:

BeanDefinition bd = beanFactory.getBeanDefinition("xxBean");
MutablePropertyValues mpv = bd.getPropertyValues();
if(pv.contains("xxName")) {
pv.addPropertyValue("xxName", "icoder");
}

注册BeanPostProcessor的实例,需要重载

Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

还有一点区别就是BeanFactoryPostProcessor的回调比BeanPostProcessor要早。

二、BeanPostProcessors

1、bean生成过程

首先回顾下bean的生命周期如下图:

2、BeanPostProcessors接口

public interface BeanPostProcessor {  

    /**
* Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
*/
  //实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; /**
* Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
* or a custom init-method). The bean will already be populated with property values.
*/
  //实例化、依赖注入、初始化完毕时执行
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }

如果这个接口的某个实现类被注册到某个容器,那么该容器的每个受管Bean在调用初始化方法的前后,都会获得该接口实现类的一个回调。容器调用接口定义的方法时会将该受管Bean的实例和名字通过参数传入方法,进过处理后通过方法的返回值返回给容器。

要使用BeanPostProcessor回调,就必须先在容器中注册实现该接口的类,那么如何注册呢?BeanFactory和ApplicationContext容器的注册方式不大一样:

  • 若使用BeanFactory,则必须要显示的调用其addBeanPostProcessor()方法进行注册,参数为BeanPostProcessor实现类的实例;
  • 如果是使用ApplicationContext,那么容器会在配置文件在中自动寻找实现了BeanPostProcessor接口的Bean,然后自动注册,我们要做的只是配置一个BeanPostProcessor实现类的Bean就可以了。

假如我们使用了多个的BeanPostProcessor的实现类,那么如何确定处理顺序呢?其实只要实现Ordered接口,设置order属性就可以很轻松的确定不同实现类的处理顺序了。

3、示例

3.1 applicationContext.xml

3.2 自己的业务bean

package com.meituan.hyt.test1;  

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; @Component
public class User {
@Value("老名字")
private String name;
@Value("50")
private Integer id; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}

3.3 postProcessor bean

package com.meituan.hyt.test1;  

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; public class UserPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
if(o instanceof User){
User user = (User)o;
user.setName("新名字");
user.setId(100);
return user;
}
return o;
} @Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
return o;
}
}

3.4 测试方法

package com.meituan.hyt.test1;  

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main2 {
public static void main(String[] args) {
ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) cxt.getBean("user");
System.out.println(user.toString());
}
}

3.5 执行结果

如果没有<bean id="userPostProcessor" class="com.meituan.hyt.test1.UserPostProcessor"/>
User{name='老名字', id=50}

添加<bean id="userPostProcessor" class="com.meituan.hyt.test1.UserPostProcessor"/>
User{name='新名字', id=100}

4、InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口

InstantiationAwareBeanPostProcessor是BeanPostProcessor的子接口,可以在Bean生命周期的另外两个时期提供扩展的回调接口,即实例化Bean之前(调用postProcessBeforeInstantiation方法)和实例化Bean之后(调用postProcessAfterInstantiation方法)。 其使用方法与上面介绍的BeanPostProcessor接口类似,只时回调时机不同。

三、与BeanFactoryPostProcessor接口的区别

BeanFactoryPostProcessor:允许自定义对ApplicationContext的 bean definitions 进行修饰,扩展功能。

1、实现BeanFactoryPostProcessor 接口,会被Application contexts自动发现 
2、BeanFactoryPostProcessor 仅仅对 bean definitions 发生关系,不能对bean instances 交互,对bean instances 的交互,由BeanPostProcessor的实现来处理 
3、PropertyResourceConfigurer 是一个典型的实现
 (PropertyResourceConfigurer是BeanFactoryPostProcessor的一个实现)

public interface BeanFactoryPostProcessor {

    /**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }

  BeanFactoryPostProcessor接口实现类可以在当前BeanFactory初始化后,bean实例化之前对BeanFactory做一些处理。BeanFactoryPostProcessor是针对于bean容器的,在调用它时,BeanFactory只加载了bean的定义,还没有对它们进行实例化,所以我们可以通过对BeanFactory的处理来达到影响之后实例化bean的效果。跟BeanPostProcessor一样,ApplicationContext也能自动检测和调用容器中的BeanFactoryPostProcessor。

示例1:

package com.meituan.hyt.test1;  

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; public class UserBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor doing");
}
}

applicationContext.xml中添加bean配置

<bean id="userBeanFactoryPostProcessor" class="com.meituan.hyt.test1.UserBeanFactoryPostProcessor"/> 

重新运行,结果

BeanFactoryPostProcessor doing
User{name='新名字', id=100}

示例2:

有这样的也个业务场景:

<bean id="user" class="com.gym.UserServiceImpl" >
<property name="username" value="${username_}"/>
<property name="password" value="${password_}"/>
</bean>

spring支持系统对username_进行占位符的配置为properties文件配置,试想如果我们有个配置中心,我们希望spring启动的时候,从远程配置中心取数据,而非本地文件,这里就需要我们自定义一个实现BeanFactoryPostProcessor的PropertyResourceConfigurer 实例。 
看下面的例子:

bean.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
default-autowire="byName"> <bean id="user" class="com.gym.UserServiceImpl" >
<property name="username" value="${username_}"/>
<property name="password" value="${password_}"/>
</bean> <bean id="myFactoryPostProcessor" class="com.gym.MyFilePlaceHolderBeanFactoryPostProcessor"/>
</beans>

模拟从远程取文件:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.support.PropertiesLoaderUtils; /**
* @author xinchun.wang
*/
public class MyFilePlaceHolderBeanFactoryPostProcessor
extends PropertyPlaceholderConfigurer implements InitializingBean{ public void afterPropertiesSet() throws Exception {
List<Properties> list = new ArrayList<Properties>();
Properties p = PropertiesLoaderUtils.loadAllProperties("config.properties");
list.add(p);
//这里是关键,这就设置了我们远程取得的List<Properties>列表
setPropertiesArray(list.toArray(new Properties[list.size()]));
} }

javaBean配置:

public class UserServiceImpl implements IUserService{
private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); public UserServiceImpl(){
logger.info("UserServiceImpl 构造函数 ");
} private String username;
private String password; public String getUsername() {
return username;
} public String getPassword() {
return password;
} public void setUsername(String username) {
logger.info("UserServiceImpl setUsername {}",username);
this.username = username;
} public void setPassword(String password) {
logger.info("UserServiceImpl setPassword {}",password);
this.password = password;
} @Override
public String toString() {
return "UserServiceImpl [username=" + username + ", password="
+ password + "]";
} }

测试:

public class TestApplicationContext {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:spring/applicationContext.xml");
IUserService userService = applicationContext.getBean(IUserService.class);
String password = userService.getPassword();
applicationContext.destroy();
System.out.println(password);
} }
 

spring扩展点之一:BeanFactoryPostProcessor和BeanPostProcessor的更多相关文章

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

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

  2. Spring的BeanFactoryPostProcessor和BeanPostProcessor

    转载:http://blog.csdn.net/caihaijiang/article/details/35552859 BeanFactoryPostProcessor和BeanPostProces ...

  3. Spring点滴十一:Spring中BeanFactoryPostProcessor和BeanPostProcessor区别

    Spring中BeanFactoryPostProcessor和BeanPostProcessor都是Spring初始化bean时对外暴露的扩展点.两个接口从名字看起来很相似,但是作用及使用场景却不同 ...

  4. Spring扩展:替换IOC容器中的Bean组件 -- @Replace注解

    1.背景:     工作中是否有这样的场景?一个软件系统会同时有多个不同版本部署,比如我现在做的IM系统,同时又作为公司的技术输出给其他银行,不同的银行有自己的业务实现(比如登陆验证.用户信息查询等) ...

  5. spring扩展点整理

    本文转载自spring扩展点整理 背景 Spring的强大和灵活性不用再强调了.而灵活性就是通过一系列的扩展点来实现的,这些扩展点给应用程序提供了参与Spring容器创建的过程,好多定制化的东西都需要 ...

  6. BeanFactoryPostProcessor vs BeanPostProcessor

    BeanFactoryPostProcessors affect BeanDefinition objects because they are run right after your config ...

  7. Spring源码之BeanFactoryPostProcessor(后置处理器)

    Spring源码之BeanFactoryPostProcessor(后置处理器). 有点水平的Spring开发人员想必都知道BeanFactoryPostProcessor也就是常说的后置管理器,这是 ...

  8. Spring拓展接口之BeanFactoryPostProcessor,占位符与敏感信息解密原理

    前言 开心一刻 一只被二哈带偏了的柴犬,我只想弄死隔壁的二哈 what:是什么 BeanFactoryPostProcessor接口很简单,只包含一个方法 /** * 通过BeanFactoryPos ...

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

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

随机推荐

  1. 2018-2019-2 网络对抗技术 20165202 Exp6 信息搜集与漏洞扫描

    博客目录 一.实践目标 二.实践内容 各种搜索技巧的应用 DNS IP注册信息的查询 基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的查点 漏洞扫描:会扫,会看报告,会查漏洞说明,会 ...

  2. LaText中插入带上下限的求和符号

    效果如下: LaTex命令如下: \begin{equation} \label{8} z_{i}(k+1)=\sum_{j\in N_{i}(k)} a_{ij}(k)z_{i}(k),z_{i}( ...

  3. Java反射-初步入门

    Java反射-初步入门 学反射先了解什么是反射. 百度百科:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动 ...

  4. Emgu cv 学习笔记

    http://www.cnblogs.com/CoverCat/p/5003363.html emgu中imagebox与picturebox imagebox 是emgu   设置好厚,新出现的控件 ...

  5. UICollectionView 数据库元素分组 多种section分开显示

    第一遍 复杂方法 : 数据库查询一个表中userID 然后进行分类 中间去重 获得ID个数  放到section 中  显示 #pragma mark -  查询不同的ID 各数  - (void)c ...

  6. [转载][QT][SQL]sq]学习记录1_模糊搜索

    转载自:sql学习网站: http://www.w3school.com.cn/sql/index.asp 用于模糊搜索数据库的数据 语句:http://www.w3school.com.cn/sql ...

  7. java面试题08

    1.short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错? short s1 = 1; s1 = s1 + 1;编译时错误.对于shor ...

  8. 《DSP using MATLAB》示例Example7.25

    今天清明放假的第二天,早晨出去吃饭时天气有些阴,十点多开始“清明时节雨纷纷”了. 母亲远在他乡看孙子,挺劳累的.父亲照顾生病的爷爷…… 我打算今天把<DSP using MATLAB>第7 ...

  9. RF设置全局变量

    一般情况下,我们的测试用例会有很多公用数据,比如在测试购票功能的时候,可能是一直使用同一个列车号,这时候我们就没有必要在每一个Case中都去新建一个列车班次,而是设置一个全局变量: 1.Set Var ...

  10. HTML CSS 表格换行禁止 超出指定长度自动截断

    word-break:keep-all; white-space:nowrap; overflow:hidden; min-width:30px; max-width:100px;