Spring之BeanPostProcessor(后置处理器)介绍

简介: 为了弄清楚Spring框架,我们需要分别弄清楚相关核心接口的作用,本文来介绍下BeanPostProcessor接口


 为了弄清楚Spring框架,我们需要分别弄清楚相关核心接口的作用,本文来介绍下BeanPostProcessor接口

BeanPostProcessor

 该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。接口的源码如下

public interface BeanPostProcessor {
  Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

方法 说明

postProcessBeforeInitialization 实例化、依赖注入完毕,

在调用显示的初始化之前完成一些定制的初始化任务

postProcessAfterInitialization 实例化、依赖注入、初始化完毕时执行

一、自定义后置处理器演示

1.自定义处理器

package com.dpb.processor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
 * 自定义BeanPostProcessor实现类
 * BeanPostProcessor接口的作用是:
 *   我们可以通过该接口中的方法在bean实例化、配置以及其他初始化方法前后添加一些我们自己的逻辑
 * @author dengp
 *
 */
public class MyBeanPostProcessor implements BeanPostProcessor{
  /**
   * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("初始化 before--实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  /**
   * 实例化、依赖注入、初始化完毕时执行 
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("初始化 after...实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
}

注意:接口中两个方法不能返回null,如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象,因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中

2.Pojo类

public class User {
  private int id;
  private String name;
  private String beanName;
  public User(){
    System.out.println("User 被实例化");
  }
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    System.out.println("设置:"+name);
    this.name = name;
  }
  public String getBeanName() {
    return beanName;
  }
  public void setBeanName(String beanName) {
    this.beanName = beanName;
  }
  /**
   * 自定义的初始化方法
   */
  public void start(){
    System.out.println("User 中自定义的初始化方法");
  }
}

3.配置文件注册

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean class="com.dpb.pojo.User" id="user" init-method="start">
    <property name="name" value="波波烤鸭" />
  </bean>
  <!-- 注册处理器 -->
  <bean class="com.dpb.processor.MyBeanPostProcessor"></bean>
</beans>

4.测试

  @Test
public void test() {
  ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  User user = ac.getBean(User.class);
  System.out.println(user);
}

输出结果

User 被实例化
设置:波波烤鸭
初始化 before--实例化的bean对象:com.dpb.pojo.User@65e2dbf3 user
User 中自定义的初始化方法
初始化 after...实例化的bean对象:com.dpb.pojo.User@65e2dbf3 user
com.dpb.pojo.User@65e2dbf3

 通过输出语句我们也能看到postProcessBeforeInitialization方法的输出语句是在Bean实例化及属性注入后执行的,且在自定义的初始化方法之前执行(通过init-method指定)。而postProcessAfterInitialization方法是在自定义初始化方法执行之后执行的。

注意!!!

   BeanFactory和ApplicationContext两个容器对待bean的后置处理器稍微有些不同。ApplicationContext容器会自动检测Spring配置文件中那些bean所对应的Java类实现了BeanPostProcessor接口,并自动把它们注册为后置处理器。在创建bean过程中调用它们,所以部署一个后置处理器跟普通的bean没有什么太大区别。

   BeanFactory容器注册bean后置处理器时必须通过代码显示的注册,在IoC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法

/**
 * Add a new BeanPostProcessor that will get applied to beans created
 * by this factory. To be invoked during factory configuration.
 * <p>Note: Post-processors submitted here will be applied in the order of
 * registration; any ordering semantics expressed through implementing the
 * {@link org.springframework.core.Ordered} interface will be ignored. Note
 * that autodetected post-processors (e.g. as beans in an ApplicationContext)
 * will always be applied after programmatically registered ones.
 * @param beanPostProcessor the post-processor to register
 */
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

测试代码如下

@Test
public void test2() {
  //ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
  XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
  // 显示添加后置处理器
  bf.addBeanPostProcessor(bf.getBean(MyBeanPostProcessor.class));
  User user = bf.getBean(User.class);
  System.out.println(user);
}

二、多个后置处理器

 我们可以在Spring配置文件中添加多个BeanPostProcessor(后置处理器)接口实现类,在默认情况下Spring容器会根据后置处理器的定义顺序来依次调用。

public class MyBeanPostProcessor implements BeanPostProcessor{
  /**
   * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("A before--实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  /**
   * 实例化、依赖注入、初始化完毕时执行 
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("A after...实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
}
public class MyBeanPostProcessor2 implements BeanPostProcessor{
  /**
   * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("B before--实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  /**
   * 实例化、依赖注入、初始化完毕时执行 
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("B after...实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
}

配置文件注册

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean class="com.dpb.pojo.User" id="user" init-method="start">
    <property name="name" value="波波烤鸭" />
  </bean>
  <!-- 注册处理器 -->
  <bean class="com.dpb.processor.MyBeanPostProcessor"/>
  <bean class="com.dpb.processor.MyBeanPostProcessor2"/>
</beans>

测试结果

User 被实例化
设置:波波烤鸭
A before--实例化的bean对象:com.dpb.pojo.User@7fac631b user
B before--实例化的bean对象:com.dpb.pojo.User@7fac631b user
User 中自定义的初始化方法
A after...实例化的bean对象:com.dpb.pojo.User@7fac631b user
B after...实例化的bean对象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b

三、显示指定顺序

 在Spring机制中可以指定后置处理器调用顺序,通过让BeanPostProcessor接口实现类实现Ordered接口getOrder方法,该方法返回一整数,默认值为 0,优先级最高,值越大优先级越低

public class MyBeanPostProcessor implements BeanPostProcessor,Ordered{
  /**
   * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("A before--实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  /**
   * 实例化、依赖注入、初始化完毕时执行 
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("A after...实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  @Override
  public int getOrder() {
    // TODO Auto-generated method stub
    return 10;
  }
}
public class MyBeanPostProcessor2 implements BeanPostProcessor,Ordered{
  /**
   * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("B before--实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  /**
   * 实例化、依赖注入、初始化完毕时执行 
   * 注意:方法返回值不能为null
   * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
   * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
   */
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("B after...实例化的bean对象:"+bean+"\t"+beanName);
    // 可以根据beanName不同执行不同的处理操作
    return bean;
  }
  @Override
  public int getOrder() {
    // TODO Auto-generated method stub
    return 2;
  }
}

测试输出结果

User 被实例化
设置:波波烤鸭
B before--实例化的bean对象:com.dpb.pojo.User@7fac631b user
A before--实例化的bean对象:com.dpb.pojo.User@7fac631b user
User 中自定义的初始化方法
B after...实例化的bean对象:com.dpb.pojo.User@7fac631b user
A after...实例化的bean对象:com.dpb.pojo.User@7fac631b user
com.dpb.pojo.User@7fac631b

数值越大的优先级越低,所以A的输出就在后面了。

~好了通过本文详细大家对于BeanPostProcessor接口的作用应该比较清楚了。


相关文章
|
4月前
|
Java Spring
Spring中那些BeanPostProcessor在Bean实例化过程中的作用
Spring中那些BeanPostProcessor在Bean实例化过程中的作用
48 1
|
3月前
|
Java 数据库连接 API
深入Spring原理-3.Bean的后置处理器
深入Spring原理-3.Bean的后置处理器
26 0
|
4月前
|
XML Java 程序员
spring-bean的生命周期和怎么配置spring-bean的后置处理器
spring-bean的生命周期和怎么配置spring-bean的后置处理器
36 0
|
5月前
|
Java Spring
Spring后置处理器中的InstantiationAwareBeanPostProcessor详解
Spring后置处理器中的InstantiationAwareBeanPostProcessor详解
25 0
|
7月前
|
XML 开发框架 Java
聊聊Spring扩展点BeanPostProcessor和BeanFactoryPostProcessor
今天聊一聊spring中很重要的两个扩展点BeanPostProcessor和BeanFactoryPostProcessor,spring之所以如次强大,是因为它提供了丰富的功能给我们使用,但是我觉得最强大的是它扩展点,因为有了各种扩展点,我们才能去开发一些自己的需求,一个框架的强大之处也在于它能否灵活的配置,能够支持很好的扩展。
37 0
|
8月前
|
Java Spring 容器
深入理解Spring源码之bean的生命周期控制器BeanPostProcessor
深入理解Spring源码之bean的生命周期控制器BeanPostProcessor
|
9月前
|
安全 Java Spring
SpringBoot整合Spring Security,自定义登录成功/失败处理器,配置登录人数(三)
一般采用的是实现接口的方式:implements AuthenticationSuccessHandler 但是如果想要实现登录成功后跳转回登录前的页面可以直接继承SavedRequestAwareAuthenticationSuccessHandler这个类,该类的父类SimpleUrlAuthenticationSuccessHandler实现了AuthenticationSuccessHandler。
212 0
|
9月前
|
Java 开发者 Spring
Spring 中后置处理器的作用?
Spring 中后置处理器的作用?
126 0
|
9月前
|
SpringCloudAlibaba Java 中间件
Spring扩展点(一):后置处理器PostProcessor
`Spring`框架中大致提供了以下三个核心后置处理器:**`BeanDefinitionRegistryPostProcessor`,`BeanFactoryPostProcessor`,`BeanPostProcessor`**,其他的后置处理器都是继承自这三个
114 0
|
29天前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
43 0