Spring提供了两种后处理bean的扩展接口,分别为 BeanPostProcessor 和BeanFactoryPostProcessor,两者在使用上是有所区别的。工厂在前,bean对象在后。在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做⼀些事情,在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做⼀些事情。
注意:对象不一定是springbean,但springbean⼀定是个对象
(1)BeanPostProcessor
BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean。该接⼝提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行,具体这个初始化方法指的是什么方法,类似我们在定义bean时,xml中定义的init-method所指定的方法。
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
定义⼀个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进⾏处理。如果要对具体的某个bean处理,可以通过方法的形参进行判断,两个类型参数分别为Object和String,第⼀个参数是每个bean的实例,第⼆个参数是每个bean的name或者id属性的值。所以我们可以通过第⼆个参数,来判断我们将要处理的具体的bean。如下图,我们想要对lazyBean对象在初始化前后进行处理,这里的初始化就包括init-method属性中指定的initMethod方法。
注意:处理是发生在Spring容器的实例化和依赖注入之后。
<bean id="lazyBean" class="com.nanmao.LazyBean" init-method="initMethod" destroy-method="destroyMethod"/>
/**
* 拦截实例化后的对象(实例化并且属性注入了),可以根据beanName来对特定的bean进行初始化前后的处理
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("lazyBean".equals(beanName)){
System.out.println("MyBeanPostProcessor 拦截bean 初始化之前Before处理");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("lazyBean".equals(beanName)){
System.out.println("MyBeanPostProcessor 拦截bean 初始化之后After处理");
}
return bean;
}
}
我们来看下SpringBean的生命周期,如下图。
承接上面的代码,以LazyBean作为演示,实现BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean、BeanPostProcessor对应的方法,我们来打印下bean生命周期中的处理顺序:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class LazyBean implements BeanNameAware, BeanFactoryAware,
ApplicationContextAware, InitializingBean, DisposableBean {
public LazyBean() {
System.out.println("lazyBean无参构造初始化------");
}
@Override
public void setBeanName(String s) {
System.out.println("bean id是:" + s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("创建bean的上层bean工厂是:" + beanFactory);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("高级容器接口ApplicationContext:" + applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean 接口中afterPropertiesSet方法");
}
public void initMethod() {
System.out.println("xml中init-method属性对应的初始化方法");
}
@PostConstruct
public void postConstruct() {
System.out.println("注解@PostConstruct对应的初始方法");
}
//===================bean的销毁相关方法===================
public void destroyMethod() {
System.out.println("xml中destroy-method属性对应的销毁方法");
}
@PreDestroy
public void preDestroy() {
System.out.println("注解@PreDestroy对应的销毁方法");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean接口中的销毁方法");
}
}
public class IocXmlTest {
@Test
public void TestIocContainer() {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Object lazyBean = applicationContext.getBean("lazyBean");
System.out.println(lazyBean);
System.out.println("===============销毁方法==============");
applicationContext.close();
}
}
控制台输出:
lazyBean无参构造初始化------
bean id是:lazyBean
创建bean的上层bean工厂是:org.springframework.beans.factory.support.DefaultListableBeanFactory@42eca56e: defining beans [myBeanPostProcessor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,accountDao,transferService,connectionUtils,transactionManager,proxyFactory,lazyBean,companyBean]; root of factory hierarchy
高级容器接口ApplicationContext:org.springframework.context.support.ClassPathXmlApplicationContext@6d1e7682, started on Sun Aug 29 23:08:18 CST 2021
MyBeanPostProcessor 拦截bean 初始化之前Before处理
注解@PostConstruct对应的初始方法
InitializingBean 接口中afterPropertiesSet方法
xml中init-method属性对应的初始化方法
MyBeanPostProcessor 拦截bean 初始化之后After处理
com.nanmao.LazyBean@19d37183
===============销毁方法==============
注解@PreDestroy对应的销毁方法
DisposableBean接口中的销毁方法
xml中destroy-method属性对应的销毁方法
注意:注解@PostConstruct和注解@PreDestroy的执行过程要早于xml中init-method属性和destroy-method属性配置的对应的方法
(2) BeanFactoryPostProcessor
BeanFactory级别的处理,是针对整个Bean的工厂进行处理,典型应用:PropertyPlaceholderConfigurer。
@FunctionalInterface
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;
}
此接口只提供了⼀个方法,方法参数为ConfigurableListableBeanFactory。该参数类型定义了⼀些方法,其中有个方法名为getBeanDefinition的⽅法,我们可以根据此方法,找到我们定义bean 的BeanDefinition对象。然后我们可以对定义的属性进行修改,以下是BeanDefinition中的方法:
方法法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。
BeanDefinition对象:我们在 XML 中定义的 bean标签,Spring 解析 bean 标签成为⼀个JavaBean,这个JavaBean 就是 BeanDefinition。
注意:调用BeanFactoryPostProcessor方法时,这时候bean还没有实例化,此时bean刚被解析成BeanDefinition对象。