Spring bean的生命周期

56 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情

Spring bean生命周期流程图

image.png

  1. 首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化
  2. 按照Bean定义配置信息,注入所有的属性
  3. 如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id
  4. 如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory
  5. 如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入改Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext
  6. 如果该Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法
  7. 如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法
  8. 如果Bean配置了init-method方法,则会执行init-method配置的方法
  9. 如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法
  10. 经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,生命周期就交给调用方管理了,不再是Spring容器进行管理了
  11. 容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法
  12. 如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此整个Bean的生命周期结束

代码演示

  • 创建一个Person类,该类实现了BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean五个接口
public class Person implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private String name;

    public Person() {
        System.out.println("Person类构造方法");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("set方法被调用");
    }

    // 自定义的初始化函数
    public void myInit() {
        System.out.println("myInit被调用");
    }

    // 自定义的销毁方法
    public void myDestroy() {
        System.out.println("myDestroy被调用");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("setBeanName被调用,beanName:" + s);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory被调用,beanFactory");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("setApplicationContext被调用");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet被调用");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("destroy被调用");
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '' +
                '}';
    }

}
  • 创建一个MyBeanPostProcessor类,该类实现了BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization被调用");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization被调用");
        return bean;
    }
}
  • applicationContext.xml文件中配置
    • 配置bean的id为person,并且配置了init-method和destroy-method,为该Bean配置了属性name为RG的值
    • 配置bean的id为postProcessor
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="com.rg.domain.Person" init-method="myInit" destroy-method="myDestroy">
        <property name="name" value="RG"/>
    </bean>

    <!--  配置自定义的后置处理器  -->
    <bean id="postProcessor" class="com.rg.processor.MyBeanPostProcessor"/>

</beans>
  • 测试类
@Test
public void personTest() {

    System.out.println("开始初始化容器");
    // 获取到了spring上下文对象,借助上下文对象可以获取到IOC容器中bean对象
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    System.out.println("xml加载完毕");
    // 使用上下文对象从IOC容器中获取到了bean对象
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
    System.out.println("关闭容器");
    applicationContext.close();

}
  • 打印结果

image.png