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日

相关文章

  • Linux折腾记(十):Bash脚本编程语言中的美学与哲学

    让我来详细讲解一下“Linux折腾记(十):Bash脚本编程语言中的美学与哲学”的完整攻略。 Bash脚本编程语言中的美学与哲学 Bash是Linux和Unix操作系统上使用最为广泛的一种脚本编程语言,支持许多快速编写脚本的便捷特性和基本编程思想,但同时也继承了Unix哲学的精湛技艺。Bash脚本编程语言的美学和哲学对于每位工程师来说都至关重要,掌握这些美学…

    Java 2023年5月26日
    00
  • 这么优雅的Java ORM没见过吧!

    首先,我们需要了解Java ORM的概念。ORM(Object Relational Mapping)是指对象关系映射,是一种将面向对象的程序与关系型数据库之间进行数据转换的技术。Java中有很多ORM框架,如Hibernate、MyBatis、JPA等,它们可以帮助开发者更加方便、高效地访问数据库。 接下来,我们来了解一款优雅的Java ORM框架——Jo…

    Java 2023年5月20日
    00
  • java String类常用方法练习小结

    下面我将详细讲解Java String类常用方法练习小结的攻略。 简介 Java中的字符串属于对象,并且在Java中字符串是不可变的。String类提供了很多常用的方法来操作字符串,下面是本文讲解的常用方法: charAt(int index):返回指定索引处的字符。 indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引。 …

    Java 2023年5月27日
    00
  • Spring Boot之FilterRegistrationBean-自定义Filter详解

    下面是对于“Spring Boot之FilterRegistrationBean-自定义Filter详解”的完整攻略。 什么是FilterRegistrationBean? FilterRegistrationBean是Spring提供的一个Bean,用于将Filter(过滤器)注册到Servlet容器中的过程中进行拦截,进而实现自定义Filter。 如何使…

    Java 2023年5月31日
    00
  • Mybatis Update操作返回值问题

    关于MyBatis Update操作返回值问题的完整攻略,我将以下面的方式进行详细讲解: 1. Update操作返回值问题的背景 通常我们对数据进行CRUD操作时,无论是使用MyBatis还是Hibernate这样的ORM框架,我们都需要考虑执行操作之后返回的结果问题,Update也不例外。对于Update操作,就需要考虑它的返回值。 对于MyBatis,我…

    Java 2023年5月20日
    00
  • 【深入浅出Spring原理及实战】「源码调试分析」深入源码探索Spring底层框架的的refresh方法所出现的问题和异常

    学习Spring源码的建议 阅读Spring官方文档,了解Spring框架的基本概念和使用方法。 下载Spring源码,可以从官网或者GitHub上获取。 阅读Spring源码的入口类,了解Spring框架的启动过程和核心组件的加载顺序。 阅读Spring源码中的注释和文档,了解每个类和方法的作用和用法。 调试Spring源码,可以通过IDEA等工具进行调试…

    Java 2023年4月24日
    00
  • 用jquery获取select标签中选中的option值及文本的示例

    获取select标签中选中的option值及文本是jQuery中的常用操作。下面是完整的攻略: 获取选中的option值 使用val()方法获取选中的option的值,示例代码如下: // HTML结构 <select id="fruit"> <option value="apple">苹果&l…

    Java 2023年6月15日
    00
  • 新的Java访问mysql数据库工具类的操作代码

    下面我将详细讲解“新的Java访问MySQL数据库工具类的操作代码”的完整攻略。 简述 在Java程序中访问MySQL数据库通常需要使用JDBC驱动,JDBC驱动是一组API,用于与不同的关系型数据库进行通信。使用JDBC驱动连接MySQL数据库可以使用原生JDBC API,也可以使用更方便的第三方库,如JdbcTemplate和MyBatis等。 我们可以…

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