spring的后置处理器——BeanPostProcessor以及spring的生命周期

摘要:
关于这两个方法的调用定时,请参阅spring源代码注释。当容器中有多个BeanPostProcessor实现类时,它们将按照在容器中注册的顺序执行。对于用户定义的BeanPostProcessor实现类,还可以让它实现Ordered接口的自定义排序。Spring提供了许多BeanPostProcessor的实现类,例如用于@Autowired annotation的AutowiredAnnotationBeanPostProcessor,用于Spring AOP动态代理的AnnotationWareAspectJAutoProxyCreator等等,而不是bean本身的对象。春天什么时候完成了这一步?

后置处理器的调用时机

BeanPostProcessor是spring提供的接口,它有两个方法——postProcessBeforeInitialization、postProcessAfterInitialization。关于这两个方法的调用时机,可以参考spring源码注释。

    /**
     * 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.*/
    @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.*/
    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

从源码注释中可以看出,postProcessBeforeInitialization方法会在bean实例化和属性设置之后,自定义初始化方法(参考https://www.cnblogs.com/dubhlinn/p/10664402.html提到的3种方式)之前被调用,而postProcessAfterInitialization方法会在自定义初始化方法之后被调用。当容器中存在多个BeanPostProcessor的实现类时,会按照它们在容器中注册的顺序执行。对于自定义BeanPostProcessor实现类,还可以让其实现Ordered接口自定义排序。

后置处理器的注册方式

在ApplicationContext容器中,只需要按普通的bean注册即可;

但是在BeanFactory容器中,需要显示的调用addBeanPostProcessor()方法才能注册。

import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

/**
 * 自定义后置处理器
 * 用于在bean的初始化前后进行扩展
 * 这里的初始化,指的是初始化阶段调用的方法,
 * 例如@Bean注解的initMethod、spring提供的InitializingBean接口、jsr-250提供的@PostConstruct接口
 * 当容器中存在多个后置处理器时,默认会按照其在容器中注册的顺序执行
 * 对于自定义后置处理器,也可以通过实现Ordered接口来自定义其执行顺序,数字越大优先级越低
 */
public class AppleBeanPostProcessor implements BeanPostProcessor, Ordered {

    /**
     * 在初始化前执行的扩展逻辑
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("apple".equals(beanName)) {
            System.out.println("创建了苹果对象...");
        }
        return bean;
    }

    /**
     * 在初始化后执行的扩展逻辑
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("apple".equals(beanName)) {
            System.out.println("苹果对象初始化完成...");
        }
        return bean;
    }

    @Override
    public int getOrder() {
        return 3;
    }
}
/**
 * 用注册普通bean的方式注册自定义后置处理器
 */
@Configuration
@Import(value = {AppleBeanPostProcessor.class})
public class LifeBeanConfig2 {
}

后置处理器的作用

简单的说,后置处理器用于bean对象初始化前后进行逻辑增强。spring提供了BeanPostProcessor的很多实现类,例如AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现,AnnotationAwareAspectJAutoProxyCreator用于SpringAOP的动态代理等等。除此之外,我们还可以自定义BeanPostProcessor的实现类,在其中写入需要的逻辑。下面以AnnotationAwareAspectJAutoProxyCreator为例,说明后置处理器是怎样工作的。我们都知道springAOP的实现原理是动态代理,最终放入容器的是代理类的对象,而不是bean本身的对象,那么spring是什么时候做到这一步的?就是在AnnotationAwareAspectJAutoProxyCreator后置处理器的postProcessAfterInitialization方法,即bean对象初始化完成之后,后置处理器会判断该bean是否注册了切面,如果是,则生成代理对象注入容器

    /**
     * Create a proxy with the configured interceptors if the bean is
     * identified as one to proxy by the subclass.
     * @see #getAdvicesAndAdvisorsForBean
     */
    @Override
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }

spring的生命周期

所谓spring的生命周期,是指一个bean对象在容器中从创建到销毁的过程,大致会经历如下过程:

1. 执行bean的构造方法,生成bean对象

2. 执行bean的set方法,注入属性

3. 如果容器中存在BeanPostProcessor的实现类,则执行它们的postProcessorBeforeInitialization方法

4. 如果bean实现了InitializingBean接口,则执行afterPropertiesSet方法

5. 如果<bean>标签或@Bean注解中定义了init-method/initMethod,则执行其引用的方法

6. 如果容器中存在BeanPostProcessor的实现类,则执行它们的postProcessorAfterInitialization方法

7. 关闭容器时,如果bean实现了DisposableBean接口,则执行destroy方法

8. 关闭容器时,如果<bean>标签或@Bean注解中定义了destroy-method/destroyMethod,则执行其引用的方法

免责声明:文章转载自《spring的后置处理器——BeanPostProcessor以及spring的生命周期》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇shell命令行快捷键初探jquery之强大丰富的选择器下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

在Tomcat服务器中启动SpringBoot项目原理(简化版)

总的来说,tomcat方式启动WAR包项目, tomcat会查询context上下文中实现ServletContainerInitializer接口的类,然后调用类的onStartup(Set<Class<?>> c, ServletContext ctx)方法 Spring的SpringServletContainerInitia...

MIPI DSI 和 D-PHY 初始化序列

MIPI DSI 和 D-PHY 初始化序列 2015-12-29 深圳 南山平山村 曾剑锋 参考文档: i.MX 6Dual/6Quad Multimedia Appl...

java web定时任务---quartz

写在前面:   前面有简单的记录下Timer定时的用法,但是在此次项目中,选择的是quartz来完成定时操作任务的。两者都可以完成定时操作,但是spring可以整合quartz,并且配置起来也比较简便,还可以同时跑多个任务。就选择了quartz,quartz的用法也很强大,这里也是简单的记录下。   第一步还是需要写自己的任务类,如果有涉及到对数据库的增删...

ogg初始化抽取的快速配置方法一: 将存量数据落地为标准trail

源端抽取进程 此进程与普通的select操作类似,只是从某个时间点开始读取表里的数据。 exinit.prm extract exinit userid ogg, password ogg reportcount every 1 miniutes rate extfile ./dirdat/ei, MEGABYTES 2000 table schema.X...

Camera Service

上面这张图比较清楚的表现了camera provider进程在camera架构中位置,作为承上启下的部分,和cameraserver进程和底层的驱动交互,camera provider进程非常重要,camera HAL层几乎全部运行在camera provider进程中完成。 首先看下camera provider所在源码中的位置:hardware/in...

JAVA继承初始化过程

我们有必要对整个初始化过程有所认识,其中包括继承,对这个过程中发生的事情有一个整体性的概念。请观察下述代码: //: Beetle.java // The full process of initialization. class Insect { int i = 9; int j; static int x1 = prt("sta...