生命周期BeanPostProcessor(3)---Spring源码从入门到精通(九)

简介: 生命周期BeanPostProcessor(3)---Spring源码从入门到精通(九)

上篇文章主要介绍了Bean生命周期,bean生命周期:创建bean--->初始化init--->销毁destory,而初始化和销毁是可以用@Bean指定的,或者用@PostCoustruct@preDestory注解,或者用InitializingBean和DisposableBean接口都能指定调用的初始化和销毁方法:

Bean生命周期(2)---Spring源码从入门到精通(八)


这篇主要介绍BeanPostProcessor,在spring框架非常重要,里面有两个接口,一个是postProcessBeforeInitialization 和 postProcessAfterInitialization两个方法,顾名思义,前者在类初始化前调用,后者在类初始化之后调用。

下面主要分为三个部分:

1、BeanPostProcessor实用。

2、BeanPostProcessor源码解析。

3、Spring底层使用BeanPostProcessor。


1、BeanPostProcessor实用


先自定义类MyBeanPostProcessor实现接口,会重写里面的两个方法,可以打印出当前初始化的类。


/**
 * 自定义类实现beanPostProcessor接口,两个重写的方法在bean初始化前后调用。
 *
 * 初始化之前用populateBean()方法,给bean属性赋值
 * 初始化开始:
 * 「
 * applyBeanPostProcessorsBeforeInitialization()初始化之前调用的方法 , 接口BeanPostProcessor
 * invokeInitMethods()方法初始化 ,执行bean初始化
 * applyBeanPostProcessorsAfterInitialization()初始化之后调用的方法 , 接口BeanPostProcessor
 * 」
 *
 * @author keying
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(
            "postProcessBeforeInitialization.....Before..." + bean.getClass() + ",【beanName】=" + beanName);
        return bean;
    }
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(
            "postProcessAfterInitialization.....After..." + bean.getClass() + ",【beanName】=" + beanName);
        return bean;
    }
}


junitTest还和上篇文章一样不变,直接运行,为了方便理解,再贴一遍:


@Test
    public void test() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(
            ConfigLifeCycle.class);
        System.out.println("容器创建完毕");
        //多实例情况下,需要获取组件,才会初始化,并且不会销毁
        //Object carObject = annotationConfigApplicationContext.getBean("car");
        //getDefinitionNames(annotationConfigApplicationContext);
        annotationConfigApplicationContext.close();
    }


控制台打印如下,我们创建的三个bean在初始化的前后都会打印:

image.png


2、BeanPostProcessor源码解析。


1、刚开始AnnotationConfigApplicationContext主要调用refresh()方法

image.png

2、点进去之后,refresh主要调用finishBeanFactoryInitialization方法,初始化所有单实例对象  

image.png

3、点进去之后,调用下图的beanFactory.preInstantiateSingletons方法

image.png

4、初始化单实例 bean之后,点进去此方法,可以看到getBean方法

image.png

5、点进getBean之后,可以看到下图方法,获取单实例,若获取不到,就会createBean创建对象并且返回。

image.png

6、createBean里有个doCreateBean,点进此方法,里面有个populateBean方法作用是在初始化对象之前,给bean注入信息,bean名,工厂名,之后下面的initializeBean方法,后面的方法就是处理器的调用。

image.png

   

7、点进initializaBean方法可以看到,里面有三个方法,中间invokeInitMethods方法就是初始化bean,applyBeanPostProcessorsBeforeInitialization方法为初始化之前调用的,applyBeanPostProcessorsAfterInitialization方法为初始化之后调用的。

image.png

8、点击applyBeanPostProcessorsBeforeInitialization方法,进入可以看到,遍历获取容器所有的beanPostProcessors,挨个执行beforeInitialization若返回为 null,则跳出for循环,不会执行后面的postBeforeBeforeInitialization方法。      

image.png


3、Spring底层使用BeanPostProcessor


可以传递ApplicationContext对象,用bean实现ApplicationContextAware方法,代码如下:


@Component
public class Cat implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    public Cat(){
        System.out.println("Cat...construct");
    }
    /**
     * construct 构造函数创建对象之后执行
     */
    @PostConstruct
    public void init(){
        System.out.println("cat ...PostConstruct.");
    }
    /**
     * 销毁之前调用
     */
    @PreDestroy
    public void destory(){
        System.out.println("cat ...PreDestroy");
    }
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}


源码如下,ApplicationContextAwareProcessor类就是集成了此接口,里面可以设置代码里的ApplicationContext。

image.png

BeanValidationPostProcessor类,作用在bean初始化前后进行效验,源码如下。


public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!this.afterInitialization) {
            this.doValidate(bean);
        }
        return bean;
    }
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (this.afterInitialization) {
            this.doValidate(bean);
        }
        return bean;
    }

之前用的@PostConstruct,和@PreDestroy注解也是因为BeanPostProcessor才运行的,在InitDestroyAnnotationBeanPostProcessor类里,调用invokeInitMethods方法

image.png点进invokeInitmethods方法可以看到,会用反射调用element.invoke方法,找到对应的bean

image.png

还有AutowiredAnnotationBeanPostProcessor类,就是在对象创建完之后,处理@Autowired注解获取到bean对象。


所有@Bean注入对象,其他方法注入组件,@Autowired,生命周期注解,@Async异步注解等等,都是基本BeanPostProcessor接口实现的。


简单总结:spring生命周期,主要为bean创建--->init初始化--->销毁,

单实例在容器加载完毕前,创建和初始化,多实例在获取bean的时候才会创建bean和初始化。@Bean注释可以指定init-method和destory-method来初始化和销毁,@PostConstruct注解和接口也可以实现,这些都基于BeanPostRrocessor接口,控制生命周期,并且实现此接口,可以在bean初始化前后处理事务。


相关文章
|
6天前
|
小程序 数据可视化 Java
Java+后端Spring boot 开发的全套UWB定位方案,0.1米高精度定位系统源码
UWB定位系统由硬件定位设备、定位引擎和应用软件组成。该定位系统应用软件支持PC端和移动端访问,并提供位置实时显示、历史轨迹回放、人员考勤、电子围栏、行为分析、智能巡检等功能。定位精度高达10cm,同时具备高动态、高容量、低功耗的优点。应用场景包括:隧道、化工、工厂、煤矿、工地、电厂、养老、展馆、整车、机房、机场等。
31 8
|
2天前
|
监控 Java API
【监控】spring actuator源码速读
【监控】spring actuator源码速读
6 1
|
2天前
|
监控 Java 关系型数据库
java版MES系统源码,后端采用 Spring Boot 多模块架构
MES系统采用Vue3的vue-element-plus-admin为后台,Spring Boot多模块架构,支持MySQL、Oracle等数据库,具备SaaS多租户功能。核心功能包括车间计划排程、工艺流程配置、生产质量管理、进度追踪、库存和排班管理等,全面覆盖生产运营关键环节。
java版MES系统源码,后端采用 Spring Boot 多模块架构
|
2天前
|
Java Spring
Spring源码学习——(二)
第二讲——了解BeanFactory的功能
|
2天前
|
Java Spring 容器
Spring源码学习——(一)
第一讲——了解BeanFactory和ApplicationContext
|
7天前
|
XML 存储 Java
Spring 6(一)【Spring 入门】
Spring 6(一)【Spring 入门】
|
9天前
|
Java 数据库连接 数据库
Spring日志完结篇,MyBatis操作数据库(入门)
Spring日志完结篇,MyBatis操作数据库(入门)
|
10天前
|
存储 自动驾驶 Java
Spring IoC&DI(1)—入门
Spring IoC&DI(1)—入门
11 1
|
10天前
|
JSON 前端开发 Java
Spring Web MVC入门(3)——响应
Spring Web MVC入门(3)——响应
12 1
|
10天前
|
存储 前端开发 Java
Spring Web MVC入门(2)——请求(下)
Spring Web MVC入门(2)——请求
16 0