SpringBean生命周期之五、七、十步(详解)

目录

前提

一.Bean的完整周期

1.1什么是Bean的生命周期

二.SpringBean的五步分析法

2.1理论分析 

2.2代码实现

三.Bean周期之七步分析法

3.1理论分析

3.2代码实现

四.Bean生命周期之十步分析法

4.1理论分析

4.2代码实现

五.总结

5.1五步、七步、十步的差别

5.2SpringBean周期的概况


前提

        在学习Spring的对象注入之后,我们可以了解一下,Bean对象的生命周期,更好学习到在Spring容器里,Bean经历了什么!        

ps:在日常里SrpingBean周期并不会使用,但是在面试当中经常出现!

一.Bean的完整周期

1.1什么是Bean的生命周期

      在传统java应用程序里,bean是new进行实例化的,若不会使用了,则会由Java自动进行垃圾回收!

Spring Bean 的生命周期在不同的文献和说明中可能会被划分为不同的步骤,比如五步、七步或十步。这种不同的划分方式主要是为了更详细地描述 Bean 的生命周期过程,以便开发人员更好地理解和控制 Bean 的创建、初始化和销毁过程。

  1. 五步划分:通常指的是 BeanFactory 的生命周期,包括 BeanFactory 的实例化、配置元数据定位、Bean 的定义解析、Bean 的注册和实例化。这种划分方式主要关注 Spring 容器本身的初始化过程。

  2. 七步划分:在七步划分中,通常会将 BeanPostProcessor 的前置处理和后置处理分别作为两个独立的步骤,这样可以更清晰地表达 BeanPostProcessor 在 Bean 生命周期中的作用。

  3. 十步划分:这种划分方式可能会更加详细地描述 Bean 的初始化和销毁过程,包括 BeanFactory 的初始化、Bean 的实例化、设置属性、BeanPostProcessor 的前置处理、初始化方法调用、BeanPostProcessor 的后置处理、Bean 可使用阶段、销毁前处理、销毁方法调用和销毁后处理。这种划分方式提供了更加详细的生命周期过程描述,有助于开发人员深入理解 Bean 的各个阶段。

本文由浅到深,步步剖析!

二.SpringBean的五步分析法

2.1理论分析 

所谓的⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程,Bean的五步生命周期简略分为以下五部分:

  1. 实例化 Bean(为 Bean 分配内存空间,调用无参构造方法)
  2. 设置属性(Bean 注⼊和装配,调用set方法)
  3. Bean 初始化(会调用各种各样的方法,不需要仔细了解)
  4. 使⽤ Bean
  5. 销毁 Bean(Spring会自动调用destroy方法,当然也可以使用自己定义该方法)

图中,初始化和销毁Bean其实还需要实现几个接口、重写方法,但这是七步分析和十步分析当中学习,我们暂且不提,后期的七步分析和十步分析就是剖析这些接口方法。

Bean 初始化:
  1. 实现了各种 Aware 通知的⽅法,如 BeanNameAware、BeanFactoryAware、 ApplicationContextAware 的接⼝⽅法;
  2. 执⾏ BeanPostProcessor 初始化前置⽅法;
  3. 执⾏ @PostConstruct 初始化⽅法,依赖注⼊操作之后被执⾏;
  4. 执⾏⾃⼰指定的 init-method ⽅法(该方法自己定义)
  5. 执⾏ BeanPostProcessor 初始化后置⽅法。

2.2代码实现

        在Spring容器里,会自动管理Bean的初始化、设置属性、使用、销毁各个阶段,当Spring容器销毁时,会自动销毁容器内所有的Bean,会自动调用Bean的destroy方法,但有两种情况不会调用。

  1. 如果Bean类实现了DisposableBean接口,容器会调用其destroy()方法
  2. 如果在Spring配置文件中配置了destroy-method属性,容器会调用指定的销毁方法。

接下来的代码我们使用第二种方式,将具体流程呈现:

User类:

public class User {
        private String username;

        public void setUsername(String username) {
            System.out.println("第二步:给对象的属性赋值");
            this.username = username;
        }

        public User() {
            System.out.println("第一步:实例化Bean,无参数构造方法执行了");
        }

        // 初始化Bean,为了呈现流程,自己写
        public void initBean(){
            System.out.println("第三步:初始化Bean");
        }

        // 销毁Bean,为了呈现流程,自己定义
        public void destroyBean(){
            System.out.println("第五步:销毁Bean");
        }

        @Override
        public String toString() {
            return "User{" +
                    "username='" + username + '\'' +
                    '}';
        }

}

xml文件配置:

<?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 http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    <bean id="user" class="com.school_ee.test.User"
          init-method="initBean" destroy-method="destroyBean">
             <!-- initBean和destroyBean是User类中自己定义的方法,会自动调用 -->
        <!--给属性赋值-->
        <property name="username" value="张三"/>
    </bean>
</beans>

接下来测试类测试:

public void init(){
        ApplicationContext applicationContext = new         ClassPathXmlApplicationContext("Spring.xml");
        User user = applicationContext.getBean("user", User.class);
        System.out.println("第四步:使用Bean");
        //为了呈现关闭流程、手动关闭Spring容器
        ClassPathXmlApplicationContext context = (ClassPathXmlApplicationContext) applicationContext;
        context.close();
    }

执行结果:

注意点:

  1. 只有正常关闭spring容器(调用close方法),bean的销毁方法才会被调用

  2. ClassPathXmlApplicationContext类才有close()方法,ApplicationContext中没有。

  3. 如果不希望Spring自动创建和销毁,可使配置文件中的init-method指定初始化方法,destroy-method指定销毁方法。

三.Bean周期之七步分析法

3.1理论分析

 

        所谓的七步分析,是在五步法的Bean初始化阶段将 BeanPostProcessor接口 的前置处理和后置处理分别作为两个独立的步骤。就是更加清晰的表达BeanPostProcessor 在 Bean 生命周期中的作用。

        BeanPostProcessor 接口的作用:Spring 框架提供的一个扩展点,用于在 Spring 容器实例化 Bean 和将 Bean 实例化到容器中之间的过程中,对 Bean 进行额外的处理。定义了前置处理方法和后置处理方法:

  1. 前置处理(postProcessBeforeInitialization):

    • 在 Bean 实例化后、依赖注入后,以及自定义初始化方法调用之前执行。
    • 可以用于对 Bean 进行额外的初始化操作,或者修改 Bean 的属性值。
    • 常见的使用场景包括对 Bean 进行动态代理、添加日志记录、进行安全检查等。
  2. 后置处理(postProcessAfterInitialization):

    • 在 Bean 自定义初始化方法调用后执行,也就是 Bean 已经完全初始化完成后执行。
    • 可以用于对 Bean 进行额外的操作,或者对已初始化的 Bean 进行后续处理。
    • 常见的使用场景包括对 Bean 进行缓存、注册监听器、执行特定的业务逻辑等。

3.2代码实现

        为了更好展示流程,我们自定义类实现 BeanPostProcessor 接口,并重写其中的postProcessBeforeInitialization方法和postProcessAfterInitialization方法。

自定义类实现接口:

package com.bjpowernode.spring.test;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
 
public class LogBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean初始化前,处理器的before方法执行");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化结束,处理器的after方法执行");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

xml配置:

<?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="user" class="com.school_ee.test.User"
          init-method="initBean" destroy-method="destroyBean">
                     <!-- initBean和destroyBean是User类中自己定义的方法,会自动调用 -->
        <!--给属性赋值-->
        <property name="username" value="张三"/>
    </bean>

    <!--配置Bean后处理器。这个后处理器将作用于当前配置文件中所有的bean。-->
    <bean class="com.school_ee.test.LogBeanPostProcessor" />
</beans>

测试文件不需要改变,直接上结果:

从测试结果中,我们可以发现,的的确确从初始化前后执行Before方法和after方法。

四.Bean生命周期之十步分析法

4.1理论分析

 

和七步分析做对比,额外的三步:

  1. 检查Bean是否实现了Aware相关的接口
    • BeanNameAware 接口回调 ,目的:允许 bean 在初始化阶段获取自身在 Spring 容器中的名字
    • BeanFactoryAware 接口回调,目的:允许 bean 在初始化阶段获取对 Spring 容器的引用
  2. 检查Bean是否实现了InitializingBean接口,Spring 在 bean 初始化完成后会自动调用 afterPropertiesSet() 方法,执行一些数据初始化、资源加载、连接数据库等必要操作
  3. 检查Bean是否实现了DisposableBean接口,Spring 容器在销毁该 bean 时会调用其 destroy() 方法,从而允许 bean 执行一些资源释放或者清理操作。

结论:检查你这个Bean是否实现了某些特定的接口,如果实现了这些接口,则Spring容器会调用这个接口中的方法!

4.2代码实现

user类实现所有接口的代码: 

package com.bjpowernode.spring.bean;
 
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
 
 
public class User implements
        BeanNameAware, BeanClassLoaderAware, BeanFactoryAware,
        InitializingBean, DisposableBean{
    private String username;
 
    public void setUsername(String username) {
        System.out.println("第二步:给对象的属性赋值");
        this.username = username;
    }
 
    public User() {
        System.out.println("第一步:实例化Bean,无参数构造方法执行了");
    }
 
    // 初始化Bean,需要自己写,自己配,方法名随意
    public void initBean(){
        System.out.println("第四步:初始化Bean");
    }
 
    // 销毁Bean,需要自己写,自己配,方法名随意
    public void destroyBean(){
        System.out.println("第七步:销毁Bean");
    }
 
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }
 
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("类加载器:" + classLoader);
    }
 
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("Bean工厂:" + beanFactory);
    }
 
    @Override
    public void setBeanName(String name) {
        System.out.println("Bean的名字:" + name);
    }
 
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy方法执行了");
    }
 
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean afterPropertiesSet方法执行了");
    }
}

xml配置文件不变,测试类不变,直接测试:

五.总结

5.1五步、七步、十步的差别

标准的五步:实例化--->设置属性--->初始化---->使用Bean---->销毁Bean

七步:实例化--->设置属性--->前置处理----->初始化----->后置处理---->使用Bean---->销毁Bean

十步:实例化--->设置属性--->Aware接口实现--->前置处理----->InitializingBean接口--->初始化----->后置处理---->使用Bean---->DisposableBean接口---->销毁Bean

5.2SpringBean周期的概况

(1)Spring其实就是一个管理Bean对象的工厂,它负责对象的创建,对象的销毁等。

(2)所谓的生命周期就是:对象从创建开始到最终销毁的整个过程。

(3)为什么要知道Bean的生命周期?

  1. 定制 Bean 的初始化和销毁过程:通过了解 Bean 的生命周期,开发人员可以在 Bean 初始化之前或销毁之后执行特定的操作,比如资源的初始化和释放、日志记录、权限检查等。

  2. 解决依赖关系问题:在了解 Bean 的生命周期的过程中,可以更好地理解 Spring 容器是如何管理 Bean 的创建、依赖注入以及销毁的,有助于解决 Bean 之间的依赖关系问题。

  3. 优化性能:了解 Bean 的生命周期可以帮助开发人员避免一些不必要的操作,从而提高系统的性能。比如在 Bean 的初始化阶段进行一些耗时操作,可能会影响系统的启动速度。

  4. 排查问题:当出现一些意外情况或 Bug 时,了解 Bean 的生命周期可以帮助开发人员更快地定位问题所在,从而更容易地进行排查和修复。

注:上述的Bean周期了解即可,在Spring容器里已经实现!

相关推荐

  1. springbean生命周期

    2024-04-03 11:24:05       18 阅读
  2. SpringBean详解

    2024-04-03 11:24:05       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-03 11:24:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-03 11:24:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-03 11:24:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-03 11:24:05       18 阅读

热门阅读

  1. 小程序页面滚动?

    2024-04-03 11:24:05       13 阅读
  2. Flink总结

    2024-04-03 11:24:05       15 阅读
  3. 【m122】webrtc的比较

    2024-04-03 11:24:05       13 阅读
  4. IDEA 宝贝插件

    2024-04-03 11:24:05       16 阅读
  5. IntelliJ IDEA - 快捷键 Win & Mac 对照表

    2024-04-03 11:24:05       14 阅读
  6. openshift和k8s的差别

    2024-04-03 11:24:05       12 阅读
  7. RuoYi单体版Table行内编辑

    2024-04-03 11:24:05       16 阅读
  8. 研究应用推广开源项目——提高软件技术的途径

    2024-04-03 11:24:05       15 阅读