Spring Bean 生命周期

本文详细解析了Spring框架中Bean的配置、实例化、属性注入、Aware接口、BeanPostProcessor回调、初始化方法以及销毁过程,帮助读者掌握SpringBean的完整生命周期管理。
摘要由CSDN通过智能技术生成

Spring Bean 生命周期

在这里插入图片描述

1. 配置 Bean

通过配置文件或者注解的形式,告诉 spring容器 哪些类是我们要注入容器的。

2. Bean的读取

在 spring 启动时,spring 会通过 BeanDefinitionReader 读取到我们配置的 Bean,将读取到的 Bean 存入 DefaultListableBeanFactory 类的 beanDefInitionMap 里(这里的 beanDefInitionMap 是一个 concurrentHashMap 类型的 Map 集合),每一个 Bean 都是一个 BeanDefInition 对象,这个对象封装了 Spring 对 Bean 的所有配置信息:类名,属性,构造方法参数,依赖,是否延迟加载,是否单例等。

3. 实例化阶段

在这个阶段,Spring 会将拿到的所有单例 Bean 进行实例化,在实例化的阶段,有几个 Spring 暴露给我们的接口可以使用。

3.1 BeanDefInitionRegistryPostProcessor:通常用来往 Spring 容器中注册新的 Bean

postProcessBeanFactory 方法与 BeanFactoryPostProcessor接口中的postProcessBeanFactory方法 功能一致,但是这个方法会在它之前触发

public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        BeanDefinition rootBeanDefinition = new RootBeanDefinition();
        rootBeanDefinition.setBeanClassName("com.cfz.entity.Student");
        beanDefinitionRegistry.registerBeanDefinition("stu",rootBeanDefinition);
    }

    //与 BeanFactoryPostProcessor 功能一致
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
            throws BeansException {
    }
}

3.2 BeanFactoryPostProcessor:通常用来修改已有的 Bean对象

​ 在这个方法中也可以注册新的 Bean,但是 ConfigurableListableBeanFactory 内是没有注册 Bean 的方法的,需要转型为 DefaultListableBeanFactory

public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        //修改
        BeanDefinition stu = configurableListableBeanFactory.getBeanDefinition("stu");
        stu.setBeanClassName("com.cfz.entity.User");
        //注册
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
        BeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClassName("com.cfz.entity.Student");
        defaultListableBeanFactory.registerBeanDefinition("user",beanDefinition);
    }
}

4. 初始化阶段

经过实例化后的 Bean 还只是一个“半成品”,则些 Bean 现在只是一个空壳。接下来赋予他们内容,才是重要部分。

4.1 Bean 实例的属性填充

为实例化好的 Bean 对象,注入属性,或者他们依赖的对象。在注入时有以下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;
  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没 有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;
  • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)

4.2 Aware接口属性注入

Aware接口是一种框架辅助属性注入的一种思想,其他框架中也可以看到类似的接口。框架具备高度封 装性,我们接 触到的一般都是业务代码,一个底层功能API不能轻易的获取到,但是这不意味着永远用 不到这些对象,如果用到了 ,就可以使用框架提供的类似Aware的接口,让框架给我们注入该对象 总结:处理器的作用,为Bean生命周期各个阶段提供扩展

spring中的aware接口主要是为了框架内部使用的,如果你的bean对象使用了aware接口,那么它就会和spring框架耦合,所以一般不建议自己使用。但是在阅读spring框架的源码时,你会发现很多地方都用到了aware接口,这是因为spring框架需要通过这些接口来获取和操作一些核心的组件或信息

public class User implements BeanNameAware, ApplicationContextAware, BeanFactoryAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println(beanFactory);
    }

    @Override
    public void setBeanName(String s) {
        System.out.println(s);
    }

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

运行结果:

在这里插入图片描述

4.3 BeanPostProcessor的before()方法回调

这个方法会在bean的初始化方法调用之前被Spring容器执行。这个方法的参数是bean对象和bean的名称,这个方法的返回值也是bean对象,你可以在这个方法中对bean对象进行一些处理,或者返回一个新的对象

BeanPostProcessor的before()方法回调的作用是,让你可以在bean的初始化之前,对bean进行一些自定义的操作,比如修改bean的属性,添加一些逻辑,或者代理bean的方法等。你可以在一个容器中注册多个BeanPostProcessor的实现类,它们的before()方法回调会按照顺序依次执行,你可以通过实现Ordered接口来控制执行顺序

Ordered接口不会影响组件或者bean的加载顺序和实例化顺序,只会影响它们的执行顺序。例如,如果有多个BeanPostProcessor的实现类,它们的postProcessBeforeInitialization()方法会按照Ordered接口的顺序依次执行,而postProcessAfterInitialization()方法则会按照相反的顺序执行。

public class MyBeanPostProcessor implements BeanPostProcessor {

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

4.4 自定义初始化方法init回调

通过配置文件或注解对 Bean 的自定义初始化方法。bean的自定义初始化阶段,是指在bean的属性注入完成后,但在bean的初始化方法执行前,可以通过一些方式为bean添加一些自定义的操作,比如修改bean的属性,添加一些逻辑,或者代理bean的方法等。

  • 通过配置文件初始化
<bean id="user" class="com.example.User" init-method="init">
    <property name="name" value="张三"/>
    <property name="age" value="18"/>
</bean>
public class User {
    private String name;
    private int age;
    
    public void init() {
        System.out.println("User bean is initialized");
    }
}
  • 实现InitializingBean接口,并重写afterPropertiesSet()方法。这个方法会在属性赋值后自动调用。
public class Student implements InitializingBean {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //重写初始化方法,打印学生的信息
    @Override
    public void afterPropertiesSet() {
        System.out.println("Student: name = " + name + ", age = " + age);
    }
}
  • 使用@PostConstruct注解标注一个方法。这个方法也会在属性赋值后自动调用,且优先于afterPropertiesSet()方法。
@Component
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //使用@PostConstruct注解标记一个初始化方法,打印信息
    @PostConstruct
    public void init() {
        System.out.println("Person: name = " + name + ", age = " + age);
    }
    
}

4.5 BeanPostProcessor的after()方法回调

这个方法会在bean的初始化方法调用之后被Spring容器执行。这个方法的参数是bean对象和bean的名称,这个方法的返回值也是bean对象,你可以在这个方法中对bean对象进行一些处理,或者返回一个新的对象。

BeanPostProcessor的after()方法回调的作用是,让你可以在bean的初始化之后,对bean进行一些自定义的操作,比如修改bean的属性,添加一些逻辑,或者代理bean的方法等。你可以在一个容器中注册多个BeanPostProcessor的实现类,它们的after()方法回调会按照相同的顺序依次执行,你可以通过实现Ordered接口来控制执行顺序也可以通过@Ordered注解实现。

public class MyBeanPostProcessor implements BeanPostProcessor {
  
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor 的 postProcessorAfterInitialization 方法执行");
        return null;
    }
    
}

5. 使用阶段

初始化完成之后,Bean 这时候已经可以被 Spring 所使用了。这些 Bean 分以下几种情况

  • 单例bean:这些bean只有一个实例,它们在容器启动时就被创建,并且在容器关闭时被销毁单例bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中。
  • 多例bean:这些bean每次请求都会创建一个新的实例,它们不会被容器管理,也不会被销毁[。原型bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中,但是每次注入都会得到一个新的对象。
  • 延迟加载bean:这些bean只有在第一次被请求时才会被创建,之后就和单例bean一样,只有一个实例,会被容器管理和销毁。延迟加载bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中。
  • 工厂bean:这些bean不是直接创建对象,而是通过实现FactoryBean接口的getObject()方法,返回一个或多个对象的实例。工厂bean可以通过getBean()方法获取,也可以通过@Autowire注解注入到其他bean中,但是需要注意区分工厂bean本身和它创建的对象。

6. 销毁阶段

bean的销毁阶段是指当应用程序结束运行或者需要清理资源时,Spring容器会销毁所有不再需要的bean。需要注意的是,只有单例bean才会被Spring容器管理和销毁,多例bean不会被Spring容器管理和销毁,它们的生命周期由使用者自行控制。这个过程包括以下两个步骤。

  • DisposableBean接口方法:如果bean实现了DisposableBean接口,那么在bean销毁前,Spring会自动调用其destroy方法,以便进行资源清理和自定义操作。
public class MyBean implements DisposableBean {

    @Override
    public void destroy() throws Exception {
        // 在这里执行销毁操作
        System.out.println("MyBean is being destroyed...");
    }
}
  • 自定义销毁方法:如果bean在配置文件中指定了destroy-method属性,或者在@Bean注解中指定了destroyMethod属性,或者在类中使用了@PreDestroy注解标记了一个方法,那么在bean销毁前,Spring会自动调用这些方法,以便进行资源清理和自定义操作。

    • xml
    <bean id="myBean" class="com.example.MyBean" destroy-method="destroyMethod"/>
    
    public class MyBean {
    
        public void destroyMethod() {
            // 在这里执行销毁操作
            System.out.println("MyBean is being destroyed...");
        }
    }
    
    • 注解
@Component
public class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //使用@PostConstruct注解标记一个销毁方法,打印信息
    @PreDestroy
    public void destroy() {
        System.out.println("Person: name = " + name + ", age = " + age);
    }
    
}

7. 总结

在这里插入图片描述

  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值