Spring学习笔记之bean生命周期

Spring学习笔记之Bean生命周期

什么是Bean生命周期

在Spring容器中,当我们需要获取一个Bean实例时,会经历一系列的过程,包括BeanDefinition解析、Bean实例化、属性注入和初始化等操作,最终才能得到我们所需要的Bean实例。这整个过程就称之为Bean生命周期。

Bean生命周期可以分为以下几个阶段:

  1. 实例化:根据BeanDefinition创建Bean实例。
  2. 属性注入:对Bean实例进行属性注入。
  3. 初始化:执行各种初始化操作,例如Bean对象实现的InitializingBean接口、@PostConstruct注解等都可以在这阶段被执行。
  4. 使用:Bean实例被使用。
  5. 销毁:当容器被关闭时,销毁Bean实例。

Bean实例化阶段

BeanDefinition解析

在Spring容器启动时,它会读取配置文件,并将配置文件中定义的BeanDefinition解析为真正的Java对象。例如,我们在配置文件中通过<bean>标签定义了一个名为userService的Bean:

<bean id="userService" class="com.example.UserService">
    <property name="userDao" ref="userDao" />
</bean>

在解析过程中,会创建一个org.springframework.beans.factory.support.DefaultListableBeanFactory对象,然后再通过registerBeanDefinition方法将定义好的Bean注册到BeanFactory当中。

DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(UserService.class)
        .addPropertyValue("userDao", userDao())
        .getBeanDefinition();
beanFactory.registerBeanDefinition("userService", beanDefinition);

Bean实例化

一旦BeanDefinition被注册成功,Spring容器就会通过反射创建出相应的Bean实例。它会调用构造函数实例化Bean对象,并在实例化时进行依赖注入。

InstantiationAwareBeanPostProcessor -> postProcessBeforeInstantiation
    -> 构造函数实例化Bean对象
InstantiationAwareBeanPostProcessor -> postProcessAfterInstantiation

在无参构造函数被调用之后,会为Bean的成员变量进行依赖注入操作。例如,我们在上面的XML中定义了userService依赖注入了userDao,则Spring容器会在实例化userService时自动注入相应的UserDao对象。

Bean实例化示例

我们通过以下的示例,来看看Spring创建Bean实例的过程:

@Component
public class MyBean implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("MyBean.setBeanName " + name);
    }

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

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

    public String hello() {
        return "Hello, " + name + "!";
    }

    @PreDestroy
    public void preDestroy() {
        System.out.println("MyBean.preDestroy");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("MyBean.destroy");
    }
}

在这个示例中,我们定义了一个名为MyBean的Bean。它实现了多个Spring生命周期接口,其中BeanNameAwareBeanFactoryAware用于获取Bean的名称和工厂,而InitializingBeanDisposableBean则用于Bean的初始化和销毁。

<bean id="myBean" class="com.example.MyBean">
    <property name="name" value="world"/>
</bean>

在XML中,我们定义了一个名为myBean的Bean,并注入了一个名为name的属性。

我们执行以下代码,来演示Spring容器创建MyBean实例的过程:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyBean myBean = context.getBean(MyBean.class);
System.out.println(myBean.hello());
context.close();

通过运行这个程序,我们会发现控制台上依次出现了以下输出:

MyBean.setBeanName myBean
MyBean.setBeanFactory org.springframework.context.annotation.AnnotationConfigApplicationContext@5a39699c: startup date [Sun Oct 20 19:39:57 CST 2019]; root of context hierarchy
MyBean.afterPropertiesSet
Hello, world!
MyBean.preDestroy
MyBean.destroy

Bean初始化阶段

Bean初始化是指Spring容器在创建完Bean实例之后,会调用org.springframework.beans.factory.config.BeanPostProcessor接口实现类的回调方法,来完成Bean对象的初始化工作。

BeanPostProcessor

在这个阶段中,Spring会调用BeanPostProcessor接口实现类的两个回调方法:

BeanPostProcessor -> postProcessBeforeInitialization
    -> 执行各种初始化工作
BeanPostProcessor -> postProcessAfterInitialization

其中的postProcessbeforeInitializationpostProcessAfterInitialization方法,分别对应Bean实例化之后的初始化操作和Bean实例化完成之后的操作。

通常我们会使用@PostConstruct注解来标注Bean的初始化方法。这样当Spring容器进行初始化时,会自动调用这个方法。

@Component
public class MyBean {

    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @PostConstruct
    public void init() {
        System.out.println("MyBean.init");
    }

    public String hello() {
        return "Hello, " + name + "!";
    }
}

Bean初始化示例

我们通过以下的示例,来看看Spring初始化Bean的过程:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

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

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor.postProcessAfterInitialization " + beanName);
        return bean;
    }
}

在这个示例中,我们定义了一个名为MyBeanPostProcessorBeanPostProcessor实现类。在初始化前和初始化后分别输出Bean的名称,以便我们更好地理解阶段。

我们执行以下代码,来演示Spring容器初始化MyBean实例的过程:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyBean myBean = context.getBean(MyBean.class);
System.out.println(myBean.hello());
context.close();

通过运行这个程序,我们会发现控制台上依次出现了以下输出:

MyBeanPostProcessor.postProcessBeforeInitialization myBean
MyBean.init
MyBeanPostProcessor.postProcessAfterInitialization myBean
Hello, world!

Bean销毁阶段

DisposableBean

在Bean销毁的阶段时,Spring容器会依次调用DisposableBean的回调方法destroy,用于执行Bean的清理工作。

DisposableBean -> destroy

与初始化阶段类似,我们还可以使用@PreDestroy注解来标注Bean的销毁方法。这样当Spring容器收到关闭的通知,会自动调用这个方法。

@Component
public class MyBean {

    @PreDestroy
    public void destroy() {
        System.out.println("MyBean.destroy");
    }
}

Bean销毁示例

我们通过以下的示例,来看看Spring销毁Bean的过程:

@Component
public class MyBean implements DisposableBean {

    @Override
    public void destroy() throws Exception {
        System.out.println("MyBean.destroy");
    }
}

在这个示例中,我们定义了一个名为MyBean的Bean,实现了DisposableBean接口。

我们执行以下代码,来演示Spring容器销毁MyBean实例的过程:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyBean myBean = context.getBean(MyBean.class);
context.close();

通过运行这个程序,我们会发现控制台上依次出现了以下输出:

MyBean.destroy

总结

Bean生命周期是Spring容器的核心部分之一,它决定了一个Bean实例的创建、初始化和销毁的过程。通过本文的介绍,我们已经了解了Spring容器在创建和销毁Bean实例时的具体过程,同时也学习了如何通过Bean生命周期接口和注解来对Bean进行定制。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring学习笔记之bean生命周期 - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • Java代码实现循环队列的示例代码

    下面是Java代码实现循环队列的完整攻略。 理解循环队列的概念 循环队列是一种常用的队列数据结构,与普通队列的区别在于,当队列的队尾到达队列的最后一个位置时,再插入一个元素时,队尾会从队列的开头重新开始(即环状)。这样既可以节省空间,又可以提高存取效率。 代码实现 定义循环队列类 首先,我们需要定义一个循环队列类。代码如下: public class Cir…

    Java 2023年5月19日
    00
  • JSP登录中Session的用法实例详解

    JSP登录中Session的用法实例详解 什么是Session Session 是在服务器端存储用户信息的最常用的方式之一。它能够跨越不同的请求并在整个会话期间保持这些信息。Session 变量存储在服务器上,当用户浏览网站时,它们的信息会被传输到服务器进行处理并返回响应页面。在 Java 中可以使用 HttpSession 对象来操作 Session。 S…

    Java 2023年6月15日
    00
  • SpringBoot+MybatisPlus+代码生成器整合示例

    下面是详细讲解“SpringBoot+MybatisPlus+代码生成器整合示例”的完整攻略。 准备工作 首先需要创建一个SpringBoot项目。在pom.xml文件中添加MybatisPlus和代码生成器的依赖。 <dependency> <groupId>com.baomidou</groupId> <arti…

    Java 2023年5月19日
    00
  • Spring Boot 入门教程

    SpringBoot入门教程 SpringBoot是一个快速开发、轻量级、微服务框架,它简化了Spring应用的开发过程,提供了自动化配置、可插拔的组件和简化的XML配置等特点,使得SpringBoot成为当前企业级Java应用开发的主流框架之一。本教程旨在帮助读者从入门到掌握SpringBoot,实现快速且高效的应用开发。 环境搭建 在开始使用Spring…

    Java 2023年5月15日
    00
  • Java程序实现导出Excel的方法(支持IE低版本)

    Java程序实现导出Excel的方法是一种常用的功能,在实际开发中也比较常见。下面将在以下几方面详细阐述Java程序实现导出Excel的方法: Excel导出的基本概念 Java程序实现导出Excel的方法 一、Excel导出的基本概念 1. Excel简介 Excel是一种常用的电子表格软件,是由微软公司开发的。Excel具有良好的数据处理和计算功能,可以…

    Java 2023年6月15日
    00
  • 什么是内存溢出?

    以下是关于内存溢出的完整使用攻略: 什么是内存溢出? 内存溢出是指程序在申请内存时,没有足够的内存空间可供使用,导致程序无法正常运行。内存溢出是一种常见的程序错误,如果不及时处理,会导致程序崩溃或者系统崩溃。 以下是一个 C++ 中内存溢出的示例: void func() { *p = new int[1000000000000]; do something…

    Java 2023年5月12日
    00
  • 详解spring boot实现多数据源代码实战

    下面我将为你详细讲解“详解springboot实现多数据源代码实战”的完整攻略。 什么是多数据源 多数据源即在一个应用中使用多个数据源,通常在企业级应用程序中使用,因为这些程序通常需要访问多个不同的数据库。使用多个数据源允许应用程序同时连接到不同的数据源,以提高性能并减少响应时间。 SpringBoot实现多数据源 SpringBoot 非常适合于创建微服务…

    Java 2023年5月15日
    00
  • Java面试题冲刺第二十天–算法(1)

    Java面试题冲刺第二十天–算法(1)攻略 前言 在面试Java开发岗位时,算法是面试官必问的一个方面。在Java面试题冲刺系列的第二十天,我们探讨的是算法相关的问题。本篇攻略主要讲解与算法相关的顶级问题、常用排序算法与查找算法。 算法相关顶级问题 什么是排序算法? 判断一个排序算法的效率主要有两个指标:时间复杂度和空间复杂度。时间复杂度通常作为衡量排序算…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部