前言
BeanPostProcessor
也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor
中定义的两个方法。
BeanPostProcessor
的源码如下:
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.
* The returned bean instance may be a wrapper around the original.
*/
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 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.
* The returned bean instance may be a wrapper around the original.
*/
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
其中postProcessBeforeInitialization
方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization
方法会在每个bean对象的初始化方法调用之后被回调。
实例:
新建两个后置处理器:
public class My1BeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("My1.Before被调用。 bean=" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("My1.After 被调用。 bean="+ bean);
return bean;
}
}
public class My2BeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("My2.Before被调用。 bean=" + bean );
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("My2.After 被调用。 bean=" + bean);
return bean;
}
}
将 Person 对象注入 Spring容器
public class Person implements InitializingBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
System.out.println("构造方法 this=" + this);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean.afterPropertiesSet 初始化 bean");
}
}
@SpringBootApplication
@Configuration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Bean
public BeanPostProcessor postBeanProcessor1() {
return new My1BeanPostProcessor();
}
@Bean
public BeanPostProcessor postBeanProcessor2() {
return new My2BeanPostProcessor();
}
@Bean
public Person person() {
Person u = new Person();
u.setName("my son");
return u;
}
}
运行结果:
这个例子证明了:1、postProcessBeforeInitialization
方法会在每一个bean对象的初始化方法调用之前回调;2、postProcessAfterInitialization
方法会在每个bean对象的初始化方法调用之后被回调。
从源码的角度这一切在哪里发生的?
AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//bean 的后置处理器中的 beforeInitialization的调用。
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
//这个包含了初始化方法的调用(InitializingBean 和 init-method)
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
}
if (mbd == null || !mbd.isSynthetic()) {
//bean 的后置处理器中的 afterInitialization的调用。
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
重点就是applyBeanPostProcessorsBeforeInitialization 、applyBeanPostProcessorsAfterInitialization两个方法:
applyBeanPostProcessorsBeforeInitialization方法:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//获取所有的 bean 的后置处理器,并遍历
for (BeanPostProcessor processor : getBeanPostProcessors()) {
//调用后置处理器的postProcessBeforeInitialization方法
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
十分简单,没有什么可说的。获取所有的后置处理器,有哪些处理器呢?
applyBeanPostProcessorsAfterInitialization也十分简单就不说了。
在所有的后置处理器中有一个CommonAnnotationBeanPostProcessor后置处理器。这一后置处理器就是@PostConstruct和@PreDestroy的以实现的载体。@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行,@PreDestroy修饰的方法会在destroy()方法之前运行。
实例:将上面的 Person 类修改一下,增加两个方法:
public class Person implements InitializingBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
System.out.println("构造方法 this=" + this);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean.afterPropertiesSet 初始化 bean");
}
@PostConstruct
public void postConstructMethod() {
System.out.println("@PostConstruct");
}
@PreDestroy
public void preDestroyMethod() {
System.out.println("@PreDestroy");
}
}
运行结果:
源码分析:
private Class<? extends Annotation> initAnnotationType;
private Class<? extends Annotation> destroyAnnotationType;
//构造方法
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);//设置initAnnotationType
setDestroyAnnotationType(PreDestroy.class);//设置idestroyAnnotationType
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
//后置处理器的实现postProcessBeforeInitialization
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
}
return bean;
}
//后置处理器的实现postProcessAfterInitialization
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
在构造方法中,设置了属性initAnnotationType和idestroAnnotationType。后置处理器的实现postProcessAfterInitialization方法直接返回bean。最重要的就是postProcessBeforeInitialization方法,这一方法中调用了两个方法:findLifecycleMetadata方法是用来获取bean中被@PostConstruct和@PreDestroy修饰的方法。invokeInitMethods方法用来调用被@PostConstruct和@PreDestroy修饰的方法。简单说就是一个负责获取、一个负责调用。
findLifecycleMetadata方法:
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
//核心方法
return buildLifecycleMetadata(clazz);
}
// lifecycleMetadataCache是一个map,用来做缓存
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);//获取缓存中的数据
if (metadata == null) {//缓存中为空
synchronized (this.lifecycleMetadataCache) {//加锁
metadata = this.lifecycleMetadataCache.get(clazz);//再次获取
if (metadata == null) {//再判断为空
//核心方法
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);//放入缓存
}
return metadata;
}
}
return metadata;
}
//核心方法
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
final boolean debug = logger.isDebugEnabled();
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//this.initAnnotationType是在构造方法中设置的@PostConstruct。
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {//判断是否有@PostConstruct修饰的方法。
//将方法包装成LifecycleElement,并放入currInitMethods集合中
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
}
//this.destroyAnnotationType是在构造方法中设置的@PreDestroy
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
//将方法包装成LifecycleElement,并放入currDestroyMethods集合中
currDestroyMethods.add(new LifecycleElement(method));
}
});
initMethods.addAll(0, currInitMethods);//将currInitMethods放入initMethods集合中
destroyMethods.addAll(currDestroyMethods);//将currDestroyMethods放入destroyMethods集合中
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
//最后再将clazz, initMethods, destroyMethods包装成LifecycleMetadata。
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
findLifecycleMetadata方法获取LifecycleMetadata对象中含 initMethods、destroyMethods这两个集合,
一个包含bean中所有@PostConstruct修饰的方法,一个包含bean中所有@PreDestroy修饰的方法。
所需的信息准备完成,invokeInitMethods方法开始调用
public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
//获取LifecycleMetadata中的initMethods集合
Collection<LifecycleElement> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {//集合不为空
boolean debug = logger.isDebugEnabled();
for (LifecycleElement element : initMethodsToIterate) {//遍历集合
if (debug) {
logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
element.invoke(target);//调用方法。
}
}
}
destroyMethods集合中的方法在bean销毁时才能被调用,这里就不在赘诉。