BeanPostProcessor介绍
BeanPostProcessor 接口使得程序可以在Bean被初始化的前后执行自定义动作,如检查或更改Bean 的属性值、包装即将注册到BeanFactory 的singletonObjects 中的原对象等。 BeanPostProcessor 接口提供了如下方法:
方法 | 描述 |
---|
Object postProcessBeforeInitialization(Object bean, String beanName) | 在容器调用Bean 的InitializingBean#afterPropertiesSet() 或自定义的init-method 之前,调用该方法进行处理;传入的bean对象属性此时已经装配好。 | Object postProcessAfterInitialization(Object bean, String beanName) | 在容器调用Bean 的InitializingBean#afterPropertiesSet() 或自定义的init-method 之后,调用该方法进行处理;传入的bean对象属性此时已经装配好。 |
BeanPostProcessor执行流程
BeanPostProcessor 的执行会在Bean 实例化并装配好属性之后,before和after之间会插入Bean 的AfterPropertiesSet() 和init-method 的执行。 下图能比较好的反应出过程:
BeanPostProcessor使用
接下来写个例子。全量代码会在最后贴出来,直接CV运行即可。
Book
Book 类,它实现了InitializingBean 接口,其afterPropertiesSet() 方法仅输出一行信息用来记录执行流程;还有一个customInit() 方法使其加入到Spring 的init-method 的执行过程;该类还有一个show() 方法,用来在后面的BeanPostProcessor 处理器中对原始的Book 对象生成一个代理类,该代理类将对show() 方法进行增强处理,用来让咱们的BeanPostProcessor 能实际干点事儿。
public class Book implements InitializingBean {
private String name;
private String author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public void show() {
System.out.printf("book#show():%s\n", this);
}
public void customInit() {
System.out.printf("%-70s:%s{%s}%n", "------Book#customInit", this.getClass().getSimpleName(), this);
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.printf("%-70s:%s{%s}%n", "------Book#afterPropertiesSet", this.getClass().getSimpleName(), this);
}
}
BookProxyBeanPostProcessor
BookProxyBeanPostProcessor 实现了BeanPostProcessor 接口;在其postProcessBeforeInitialization() 方法中对Book 类型进行判断,如果是Book 类型则使用CGLIB生成其代理,用来增强Book#show() 方法,在其前后各打印一句话。
public class BookProxyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%-70s:%s{%s}%n",
"------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
bean.getClass().getSimpleName(),
bean);
if (Book.class.equals(bean.getClass())) {
System.out.printf("\033[1;33m%-70s:对[%s]的\033[1;31mshow()\033[1;33m方法进行增强 \033[0m%n",
"------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
bean.getClass().getSimpleName());
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Book.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> {
if (!method.equals(Book.class.getMethod("show"))) {
return methodProxy.invokeSuper(obj, args);
}
System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行前");
Object result = methodProxy.invokeSuper(obj, args);
System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行后");
return result;
});
Book book = (Book) enhancer.create();
book.setName(((Book) bean).getName());
book.setAuthor(((Book) bean).getAuthor());
return book;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%-70s:%s{%s}%n",
"------BookProxyBeanPostProcessor#postProcessAfterInitialization",
bean.getClass().getSimpleName(), bean);
return bean;
}
}
main
定义一个Book 类型的GenericBeanDefinition ,将Book#customInit() 添加到BeanDefinition 中,并设置MutablePropertyValues 用于初始化后的属性装配。 同时将BookProxyBeanPostProcessor 注册到容器中。
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
GenericBeanDefinition bookBeanDefinition = new GenericBeanDefinition();
bookBeanDefinition.setBeanClass(Book.class);
bookBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
bookBeanDefinition.setPropertyValues(new MutablePropertyValues()
.addPropertyValue(new PropertyValue("name", "《非暴力沟通》"))
.addPropertyValue(new PropertyValue("author", "马歇尔·卢森堡"))
);
bookBeanDefinition.setInitMethodName("customInit");
context.registerBeanDefinition("book", bookBeanDefinition);
context.registerBean("bookProxyBeanPostProcessor", BookProxyBeanPostProcessor.class);
context.refresh();
context.getBean("book", Book.class).show();
}
全量代码
package com.baiyang.beanpostprocessor;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.context.support.GenericApplicationContext;
public class BookProxyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%-70s:%s{%s}%n",
"------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
bean.getClass().getSimpleName(),
bean);
if (Book.class.equals(bean.getClass())) {
System.out.printf("\033[1;33m%-70s:对[%s]的\033[1;31mshow()\033[1;33m方法进行增强 \033[0m%n",
"------BookProxyBeanPostProcessor#postProcessBeforeInitialization",
bean.getClass().getSimpleName());
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Book.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) -> {
if (!method.equals(Book.class.getMethod("show"))) {
return methodProxy.invokeSuper(obj, args);
}
System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行前");
Object result = methodProxy.invokeSuper(obj, args);
System.out.printf("\033[1;33m%-70s\033[0m%n", "Book#show()执行后");
return result;
});
Book book = (Book) enhancer.create();
book.setName(((Book) bean).getName());
book.setAuthor(((Book) bean).getAuthor());
return book;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.printf("%-70s:%s{%s}%n",
"------BookProxyBeanPostProcessor#postProcessAfterInitialization",
bean.getClass().getSimpleName(), bean);
return bean;
}
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
GenericBeanDefinition bookBeanDefinition = new GenericBeanDefinition();
bookBeanDefinition.setBeanClass(Book.class);
bookBeanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
bookBeanDefinition.setPropertyValues(new MutablePropertyValues()
.addPropertyValue(new PropertyValue("name", "《非暴力沟通》"))
.addPropertyValue(new PropertyValue("author", "马歇尔·卢森堡"))
);
bookBeanDefinition.setInitMethodName("customInit");
context.registerBeanDefinition("book", bookBeanDefinition);
context.registerBean("bookProxyBeanPostProcessor", BookProxyBeanPostProcessor.class);
context.refresh();
context.getBean("book", Book.class).show();
}
static class Book implements InitializingBean {
private String name;
private String author;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public void show() {
System.out.printf("book#show():%s\n", this);
}
public void customInit() {
System.out.printf("%-70s:%s{%s}%n", "------Book#customInit", this.getClass().getSimpleName(), this);
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.printf("%-70s:%s{%s}%n", "------Book#afterPropertiesSet", this.getClass().getSimpleName(), this);
}
}
}
执行结果
从执行结果即可反应出BeanPostProcessor 的执行流程。
源码解析
spring版本:5.2.9
该节源码解析仅仅只讲关键的与BeanPostProcessor 相关的位置。如果想要知其与BeanPostProcessor 前后的细节,可以针对本节的所讲述的位置自行Debug进入详细阅读。
首先是Spring容器的经典入口:refresh() 然后调用AbstractApplicationContext 所持有的实际BeanFactory (DefaultListableBeanFactory )句柄的preInstantiateSingletons() 做Bean容器的初始化工作。
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons : 进入getBean() 方法,由于我们是新创建bean,所以流程将会是getBean()->doGetBean()->createBean()->doCreateBean() 的流程,咱们一路DEBUG到doCreateBean() : 由于我们重点是在了解BeanPostProcessor 的内部执行流程上,所以上图隐藏了一些不太相关的代码,避免干扰; 此时还没有调用到BeanPostProcessor ,所以从doCreateBean 的执行流程可以看出,此时已经将Bean进行的实例化,并且装配好了属性值。 接着进入到关键方法exposedObject = initializeBean(beanName, exposedObject, mbd);
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) 从上面的initializeBean() 的流程可以看到我们首先调用了BeanPostProcessor#postProcessBeforeInitialization() ,然后执行了invokeInitMethods() 来处理bean的实现的InitializingBean 接口的afterPropertiesSet() 与自定义init-method ;最后执行BeanPostProcessor#postProcessAfterInitialization() ;
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization 从上面的方法可以看出BeanPostProcessor#postProcessBeforeInitialization 是可以改变即将注册到BeanFactory 中的实际对象的。
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeInitMethods 从上面的invokeInitMethods() 可以看到包含了InitializingBean 接口的处理与init-method 的方法处理流程; init-method 方法最终会通过反射执行。
最后就是BeanPostProcessor#postProcessAfterInitialization() 方法的执行:
至此initializeBean() 方法执行结束返回到doCreateBean() : doCreateBean() 将initializeBean() 返回的对象返回出去,一路回到getSingleton() : org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>) 可以看到此时,已经将一个经过了BeanPostProcess 处理的Bean 对象注册到了BeanFactory 中(在本例子里面是我们的BookProxyBeanPostProcessor 创建的Book 对象的代理类)。
总结
以上通过围绕BeanPostProcessor 创建一个对指定Bean 对象的代理对象,对其特定方法进行代理增强的例子,来介绍了BeanPostProcessor 的应用。 同时,通过对源码的浅析来对BeanPostProcessor 的执行前后流程进行了讲解。
|