( 六 ) Spring Bean 后置处理器-BeanPostProcessor

本文内容纲要:

- 

- 4、使用示例

( 六 ) Spring Bean 后置处理器-BeanPostProcessor

1、简介

BeanPostProcessor 接口也被称为后置处理器,通过该接口可以自定义调用Bean初始化前后执行的操作方法。

如果我们希望容器中创建的每一个bean,在创建的过程中可以执行一些自定义的逻辑,那么我们就可以编写一个类,并让他实现 BeanPostProcessor接口,然后将这个类注册到一个容器中。容器在创建bean的过程中,会优先创建实现了 BeanPostProcessor接口的 bean,然后,在创建其他bean的时候,会将创建的每一个bean作为参数,调用BeanPostProcessor的方法。而BeanPostProcessor接口的方法,即是由我们自己实现的。下面就来具体介绍一下 BeanPostProcessor的使用。

2、BeanPostProcessor 接口源码如下:

public interface BeanPostProcessor {

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

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

}

postProcessBeforeInitialization: 在 Bean 实例化、依赖注入后,初始化前调用。(初始化前是指: init-method、InitializingBean、@PostConstruct)

postProcessAfterInitialization : 在 Bean 实例化、依赖注入、初始化都完成后调用。

这两个方法有着相同的参数:

  • bean:容器正在创建的那个bean的引用;
  • beanName:容器正在创建的那个bean的名称;

3、那这两个方法何时执行呢?

这就涉及到Spring中,bean的生命周期了,下图表现了bean的生命周期:

上图中标红的两个地方就是BeanPostProcessor中两个方法的执行时机。Spring容器在创建bean时,如果容器中包含了BeanPostProcessor的实现类对象,那么就会执行这个类的这两个方法,并将当前正在创建的bean的引用以及名称作为参数传递进方法中。这也就是说,BeanPostProcessor的作用域是当前容器中的所有bean(不包括一些特殊的bean,这个后面说)。

当需要添加多个后置处理器实现类时,默认情况下 Spring 容器会根据后置处理器的定义顺序来依次调用。也可以通过实现 Ordered 接口的 getOrder 方法指定后置处理器的执行顺序。该方法返回值为整数,默认值为 0,值越大优先级越低。

4、使用示例

HelloWorld 类代码如下:

public class HelloWorld {

private String message;

public void setMessage(String message) {

this.message = message;

}

public void getMessage() {

System.out.println("Message : " + message);

}

public void init() {

System.out.println("Bean正在初始化");

}

public void destroy() {

System.out.println("Bean将要被销毁");

}

}

InitHelloWorld 类代码如下:

public class InitHelloWorld implements BeanPostProcessor, Ordered {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

System.out.println("A Before : " + beanName);

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

System.out.println("A After : " + beanName);

return bean;

}

@Override

public int getOrder() {

return 5;

}

}

需要注意的是: postProcessBeforeInitialization 和 postProcessAfterInitialization 方法返回值不能为 null,否则会报空指针异常或者通过 getBean() 方法获取不到 Bean 实例对象,因为后置处理器从Spring IoC 容器中取出 Bean 实例对象后没有再次放回到 IoC 容器中。

InitHelloWorld2 的代码如下:

public class InitHelloWorld2 implements BeanPostProcessor, Ordered {

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

System.out.println("B Before : " + beanName);

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

System.out.println("B After : " + beanName);

return bean;

}

@Override

public int getOrder() {

return 0;

}

}

Beans.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"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="helloWorld" class="com.dw.study.HelloWorld"

init-method="init" destroy-method="destroy">

<property name="message" value="Hello World!" />

</bean>

<!-- 注册处理器 -->

<bean class="com.dw.study.InitHelloWorld" />

<bean class="com.dw.study.InitHelloWorld2" />

</beans>

MainApp 类代码如下:

public class MainApp {

public static void main(String[] args) {

AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

HelloWorld obj = (HelloWorld) context.getBean("helloWorld");

obj.getMessage();

context.registerShutdownHook();

}

}

运行结果如下:

B Before : helloWorld

A Before : helloWorld

Bean正在初始化

B After : helloWorld

A After : helloWorld

Message : Hello World!

Bean将要被销毁

由运行结果可以看出: postProcessBeforeInitialization 方法是在 Bean 实例化和依赖注入后,自定义初始化方法前执行的。而 postProcessAfterInitialization 方法是在自定义初始化方法后执行的。由于 getOrder 方法返回值越大,优先级越低,所以 InitHelloWorld2 先执行。

5、使用注意事项

5.1、BeanPostProcessor依赖的bean,不会执行BeanPostProcessor的方法

当我们在BeanPostProcessor的实现类中,依赖了其他的bean,那么被依赖的bean被创建时,将不会执行它所在的BeanPostProcessor实现类实现的方法,如下所示:

@Component

public class PostBean implements BeanPostProcessor, Ordered {

// 让PostBean依赖User

@Autowired

private User user;

@Override

public Object postProcessBeforeInitialization(Object bean, String beanName)

throws BeansException {

return bean;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName)

throws BeansException {

return bean;

}

}

此时,容器在创建User这个bean时,不会执行PostBean实现的两个方法,因为由于PostBean依赖于user,所以user需要在PostBean之前创建完成,这也就意味着在user创建时,PostBean还未初始化完成,所以不会调用它的方法。

5.2、BeanPostProcessor以及依赖的bean无法使用AOP

以下是Spring官方文档中的一段话:

Because AOP auto-proxying is implemented as a BeanPostProcessor itself, neither BeanPostProcessor s nor the beans they reference directly are eligible for auto-proxying, and thus do not have aspects woven into them.

上面这段话的意思大致是说,SpringAOP代理就是作为BeanPostProcessor实现的,所以我们无法对BeanPostProcessor的实现类使用AOP织入通知,也无法对BeanPostProcessor的实现类依赖的bean使用AOP织入通知。SpringAOP实现我暂时还没有研究过,所以上面的说AOP作为BeanPostProcessor实现的意思我不是特别明白,但是我们现在只需要关注BeanPostProcessor以及它依赖的bean都无法使用AOP这一点。

本文内容总结:,4、使用示例,

原文链接:https://www.cnblogs.com/dw3306/p/15069190.html

以上是 ( 六 ) Spring Bean 后置处理器-BeanPostProcessor 的全部内容, 来源链接: utcz.com/z/362515.html

回到顶部