《B站-Spring源码解析》学习笔记(二)——Bean的生命周期

视频地址:https://www.bilibili.com/video/BV1oW41167AV
对应代码Git库地址:https://github.com/whh306318848/spring-annotation.git

  1. Bean的生命周期是指Bean的创建–初始化–销毁的过程,Bean的生命周期是由容器来管理的
  2. 关于构造(对象创建),单实例Bean是在容器启动的时候进行创建的,而多实例Bean是在每次获取的时候才进行创建的
  3. 关于初始化,初始化代码是在对象创建完成并赋值之后进行调用的
  4. 关于销毁,单实例Bean是在容器关闭的时候(即容器的close方法被调用时)进行销毁的,而多实例Bean的销毁工作容器不会进行管理
  5. 我们可以自定义Bean的初始化和销毁方法,容器会在Bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
  6. 自定义Bean的初始化和销毁共有四种方法,分别是

– 指定初始化和销毁方法
– 让Bean实现InitializingBean、DisposableBean接口定义
– 使用@PostConstruct注解和@PreDestroy注解
– 自定义类实现BeanPostProcessor接口
7. 第一种,指定初始化和销毁方法有两种方式实现
7.1. 在bean的xml配置文件中,可以为bean标签添加init-method和destory-method属性指定初始化和销毁方法,这两个方法必须没有参数,但是可以抛出异常,以上两个方法必须定义在当前对象的类里
7.2. 除了xml配置文件外,也可以使用注解的方式设置Bean的初始化和销毁方法,可以在@Bean注解中设置initMethod和destroyMethod,其值就是对应方法的方法名,以上两个方法必须定义在当前对象的类里

public class Car {
    public Car() {
        System.out.println("car constructor...");
    }

    public void init() {
        System.out.println("car init...");
    }

    public void destory() {
        System.out.println("car destory...");
    }
}

@Bean(initMethod = "init", destroyMethod = "destory")
public Car car() {
    return new Car();
}
  1. 第二种,可以通过让Bean实现InitializingBean接口的afterPropertiesSet方法和DisposableBean接口的destroy方法实现自定义初始化和销毁
@Component
public class Cat implements InitializingBean, DisposableBean {

    public Cat() {
        System.out.println("cat constructor...");
    }

    /***
     * @Author: wuhaohua
     * @Date: 2020/12/29
     * @Description: 在Bean销毁之前被调用
     **/
    @Override
    public void destroy() throws Exception {
        System.out.println("cat destroy...");

    }

    /***
     * @Author: wuhaohua
     * @Date: 2020/12/29
     * @Description: 在Bean构建之后,初始化之前被调用
     **/
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat afterPropertiesSet...");
    }
}

  1. 第三种,可以使用JSR250规范中定义的两个注解:@PostConstruct和@PreDestroy
    9.1. @PostConstruct:在Bean装配完成后,即对象创建,属性赋值完成后,执行初始化,是一个标注在方法上的注解
    9.2. @PreDestroy:在容器销毁bean之前,通知我们进行清理工作
@Component
public class Dog {

    private ApplicationContext applicationContext;

    public Dog() {
        System.out.println("dog constructor...");
    }

    /***
     * @Author: wuhaohua
     * @Date: 2020/12/29
     * @Description: 对象创建并赋值之后调用
     **/
    @PostConstruct
    public void init() {
        System.out.println("dog PostConstruct...");
    }

    /***
     * @Author: wuhaohua
     * @Date: 2020/12/29
     * @Description: 容器移除对象之前调用
     **/
    @PreDestroy
    public void destory() {
        System.out.println("dog PreDestroy...");
    }
}
  1. 第四种,实现BeanPostProcessor接口,即bean的后置处理器,是在bean初始化前后进行一些处理工作,该接口定义了两个方法,分别是postProcessBeforeInitialization(在已经创建Bean实例之后,在任何初始化方法调用之前被调用)和postProcessAfterInitialization(在Bean实例的初始化之后被调用)
    10.1. postProcessBeforeInitialization方法有两个参数,分别是bean(刚创建的实例)和beanName(该实例在容器中的名字),其返回值是后面要用的bean实例,即可返回原来的对象,也可以返回包装后的对象
    10.2. postProcessAfterInitialization方法有两个参数,分别是bean(刚创建的实例)和beanName(该实例在容器中的名字),即可返回原来的对象,也可以返回包装后的对象
/**
 * @author: wuhaohua
 * @date: Created in 2020/12/29 18:02
 * @description: 后置处理器:初始化前后进行处理工作
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    /***
     * @param bean 刚创建的实例
     * @param beanName 这个实例在容器中的名字
     * @return 将要使用的bean实例
     * @Author: wuhaohua
     * @Date: 2020/12/29 
     * @Description:
     **/
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
        return bean;
    }

    /***
     * @param bean 刚创建的实例
     * @param beanName 这个实例在容器中的名字
     * @return 将要使用的bean实例
     * @Author: wuhaohua
     * @Date: 2020/12/29
     * @Description:
     **/
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
        return bean;
    }
}

10.3. BeanPostProcessor的工作原理:

// 给bean进行属性赋值
populateBean(beanName, mbd, instanceWrapper);
initializeBean {
    // 找到所有的BeanPostProcessor,遍历,然后执行其postProcessBeforeInitialization方法,一旦某个postProcessBeforeInitialization返回null以后,后面的BeanPostProcessor就不会被执行了,整个方法就直接返回了
    applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    // 执行自定义初始化函数
    invokeInitMethods(beanName, wrappenBean, mbd);
    // 
    applyBeanPostProcessAfterInitialization(wrappedBean, beanName);
}
  1. 各个方法在Bean实例化和销毁过程中的调用顺序整理
    11.1. Bean实例化过程:
    Bean的构造函数 > BeanPostProcessor的postProcessBeforeInitialization() > @PostConstruct注解标注的方法 > InitializingBean的afterPropertiesSet() > Bean的initMethod() > BeanPostProcessor的postProcessAfterInitialization()
    11.2. Bean销毁过程:
    @PreDestroy注解标注的方法 > DisposableBean的destroy() > Bean的destroyMethod()

  2. BeanPostProcessor在Spring底层的使用
    12.1. BeanPostProcessor有非常多的实现类,很多注解都实现了该接口
    12.2. 如果组件中需要使用IOC容器,可以让组件实现ApplicationContextAware接口,该接口有一个setApplicationContext方法,其参数ApplicationContext即是IOC容器,将该方法传入的IOC容器保存起来,则该类的其他方法也可以使用这个容器
    12.3. setApplicationContext方法是在当前组件被创建之后马上调用,即构造函数调用之后马上调用的

@Component
public class Dog implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Dog() {
        System.out.println("dog constructor...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

12.4. 若需要在Bean创建成功之后进行数据校验,可以通过BeanValidationPostProcessor实现
12.5. Spring底层的bean赋值、其他组件注入、@Autowired、生命周期注解功能、@Async注解等功能,都是用BeanPostProcessor实现的

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据