Spring系列篇 -- Bean的生命周期

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: Spring系列篇 -- Bean的生命周期

前言:今天小编给大家带来的是关于Spring系列篇中的Bean的生命周期讲解。在了解Bean的生命周期建议先看Spring 的AOP的讲解。希望大家看了能够对你们学习,工作带来有效的帮助!

经典面试题目:

问题一:“ Spring容器管理JavaBean的初始化流程?”

答:“ 第一步:在【xml,configuation 注解,annotation 配置类】中配置JavaBean

         第二步:在BeanDefinitionReader解析JavaBean生成BeanDefinition,通过list集合遍历,。

          第三步:到BeanFactoryPostProcessor中,JavaBean执行自己的业务。

          第四步:spring中beanFactory,通过list集合初始化所有的Javabean对象。

          第五步:如果自己JavaBean需要调用spring上下文中的资源就需要实现*Aware感知接口。

          第六步:如果自己JavaBean已经初始化好了,则还要扩展。使用BeanFactoryPostProcessor来完成。

问题二:“ Spring中JavaBean是单例还是多例模式?”

答:“ 第一:Spring中JavaBean默认是单例模式的但可以配置成多例模式。因为:这根单例模式的特点有关:单例的特点:节约内存资源,变量容易污染。 多例的特点:占用大量资源,变量不易污染。  

        第二:单例模式:JavaBean跟着上下文初始化的” 多例模式:JavaBean在使用时才创建的,销毁跟着”

         第三:第二点并不是绝对的。

一,Bean的生命周期图

理解:Spring的生命周期主要指创建、初始化、销毁。Bean的生命周期主要由容器进行管理,我们可以自定义bean的初始化和销毁方法,容器在bean进行到生命周期的特定时间点,来调用自定义的初始化和销毁方法。

二,关于Bean的生命周期流程介绍:

1. 通过XML、Java annotation以及Java Configuration等方式加载spring bean

2. BeanDefinitionReader解析Bean的定义。Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构;该过程有点类似于实例化后的建模对象。

3. BeanDefinition:包含了多少属性和方法,例如类名、scope、属性、构造函数参数列表、依赖的bean、是否是单例、是否是懒加载等。其实就是将Bean的定义信息存储到这个BeanDefinition相应的属性中,后面对Bean的操作就直接对BeanDefinition进行,例如拿到这个BeanDefinition后,可以根据里面的类名、构造函数、构造函数参数,使用反射进行对象创建。

思路:通过查看beandefinition的原码,发现这个类中已经定义,封装了它自己的类名、构造函数、构造函数参数,所以我们拿到它这个对象我们去遍历依据反射原理可以得到实例的对象

 

4. BeanFactoryPostProcessor:是实现spring容器功能扩展的重要接口,例如修改bean属性值,实现bean动态代理等。很多框架都是通过此接口实现对spring容器的扩展,例如mybatis与spring集成时,只定义了mapper接口,无实现类,但spring却可以完成自动注入。

  > 注意:

  > 1)BeanFactoryPostProcessor在spring容器加载完BeanDefinition之后,在bean实例化之前执行的;

  > 2)对bean元数据(BeanDefinition)进行加工处理,也就是BeanDefinition属性填充、修改等操作;

       如果要对某个bean中的某个属性进行非空验证之类的操作(自定义操作),就可以实现该接口类

       BeanFactoryPostProcessor来完成扩展功能。

5. BeanFactory:Bean工厂。它按照我们的要求,生产我们需要的各种各样的bean,提供给我们使用。只是在生产bean的过程中,需要解决bean之间的依赖问题,才引入了依赖注入(DI)这种技术。也就是说依赖注入是beanFactory生产bean时为了解决bean之间的依赖的一种技术而已。

6)Aware感知接口:在实际开发中,经常需要用到Spring容器本身的功能资源

例如:BeanNameAware、ApplicationContextAware等等

BeanDefinition 实现了 BeanNameAware、ApplicationContextAware

7)BeanPostProcessor:后置处理器。在Bean对象实例化和引入注入完毕后,

在显示调用初始化方法的前后添加自定义的逻辑。(类似于AOP的绕环通知)

前提条件:如果检测到Bean对象实现了BeanPostProcessor后置处理器才会执行

Before和After方法

BeanPostProcessor

1)Before

2)调用初始化Bean(InitializingBean和init-method,Bean的初始化才算完成)

3)After

完成了Bean的创建工作

8)destory:销毁

详细介绍Bean的生命周期中单词

1 BeanDefinitionReader

在Spring中,BeanDefinitionReader是用于读取并解析配置文件的类,它在JavaBean的生命周期中起着重要的作用。

在JavaBean的生命周期中,BeanDefinitionReader主要用于实例化和属性注入阶段。它会读取配置文件中的<bean>标签,并解析其中的属性值、初始化方法和销毁方法等信息。通过解析配置文件,BeanDefinitionReader可以获取到JavaBean的类名、属性值、初始化方法和销毁方法等元数据。

在实例化阶段,BeanDefinitionReader会根据配置文件中的信息使用反射机制创建JavaBean的实例。它会根据配置文件中的<bean>标签中的class属性获取到JavaBean的类名,并使用反射机制创建JavaBean的实例。

在属性注入阶段,BeanDefinitionReader会根据配置文件中的<property>标签获取到JavaBean的属性值,并使用反射机制将属性值注入到JavaBean中。它会根据配置文件中的<property>标签中的name属性获取到属性名,然后根据name属性获取到对应的属性值,并使用反射机制将属性值注入到JavaBean中。

除了实例化和属性注入阶段,BeanDefinitionReader还可以在其他阶段发挥作用。例如,在初始化阶段,BeanDefinitionReader可以读取配置文件中的init-method属性,并将其作为初始化方法进行调用。在销毁阶段,BeanDefinitionReader可以读取配置文件中的destroy-method属性,并将其作为销毁方法进行调用。

总之,BeanDefinitionReader在JavaBean的生命周期中起着解析和读取配置文件的作用,它能够获取到JavaBean的元数据,并根据配置文件中的信息进行实例化、属性注入、初始化和销毁等操作。

2 BeanDefinition

BeanDefinition是Spring框架中的一个重要概念,它用于描述和定义一个Bean的信息。

具体来说,BeanDefinition的作用主要有以下几个方面:

1. 定义Bean的属性:BeanDefinition定义了一个Bean的属性,包括Bean的类名、作用域、是否懒加载、依赖关系等。通过BeanDefinition,可以对Bean的属性进行配置和管理。

2. 描述Bean的依赖关系:BeanDefinition描述了Bean与其他Bean之间的依赖关系。它可以指定Bean所依赖的其他Bean,以及依赖的方式(如通过构造函数注入、setter方法注入等)。通过BeanDefinition,可以实现Bean之间的依赖注入。

3. 定义Bean的初始化和销毁方法:BeanDefinition可以定义Bean的初始化方法和销毁方法。它可以指定Bean在实例化之后需要执行的初始化方法,以及在销毁之前需要执行的销毁方法。通过BeanDefinition,可以实现对Bean生命周期的管理。

4. 扩展Bean的功能:通过BeanDefinition,可以对Bean的定义进行扩展,实现自定义的功能。可以在BeanDefinition中添加AOP切面、事务管理等功能,从而实现对Bean的增强。

5. 灵活配置Bean的定义:BeanDefinition提供了灵活的配置方式,可以通过XML配置文件、注解或编程的方式来定义Bean。可以根据需要,选择合适的方式来配置Bean的定义。

总之,BeanDefinition是Spring框架中用于描述和定义Bean的信息的重要概念。它定义了Bean的属性、依赖关系、初始化和销毁方法等信息,可以实现对Bean的配置和管理。通过BeanDefinition,可以实现灵活的Bean配置和扩展,从而实现对Bean的定制化功能。

3 BeanFactoryPostProcessor

BeanFactoryPostProcessor是Spring框架中的一个扩展接口,它可以在Spring容器实例化Bean之后,对Bean的定义进行修改或扩展。

具体来说,BeanFactoryPostProcessor的作用主要有以下几个方面:

1. 修改Bean的定义:通过实现BeanFactoryPostProcessor接口,可以在Spring容器实例化Bean之前,对Bean的定义进行修改。可以添加、删除或修改Bean的属性值、作用域、依赖关系等。这样可以在不修改源代码的情况下,对Bean的定义进行动态调整。

2. 扩展Bean的定义:通过实现BeanFactoryPostProcessor接口,可以在Spring容器实例化Bean之前,对Bean的定义进行扩展。可以添加新的Bean定义,或者通过修改Bean的定义来实现自定义的扩展功能。例如,可以在Bean的定义中添加AOP切面、事务管理等功能。

3. 配置Bean的属性值:通过实现BeanFactoryPostProcessor接口,可以在Spring容器实例化Bean之前,对Bean的属性值进行配置。可以根据需要,动态地设置Bean的属性值,从而实现更灵活的配置。

4. 解析和处理Bean的定义:BeanFactoryPostProcessor接口还可以用于解析和处理Bean的定义。可以根据需要,对Bean的定义进行解析和处理,以实现特定的逻辑。例如,可以根据Bean的定义生成其他相关的Bean定义,或者根据Bean的定义进行一些逻辑判断和处理。

需要注意的是,BeanFactoryPostProcessor是在Spring容器实例化Bean之后,对Bean的定义进行修改或扩展的。它与BeanPostProcessor接口的区别在于,BeanFactoryPostProcessor是在Bean的定义阶段进行操作,而BeanPostProcessor是在Bean的实例化和初始化阶段进行操作。因此,BeanFactoryPostProcessor可以对Bean的定义进行修改,而BeanPostProcessor只能对Bean的实例进行操作。

4 BeanFactory

BeanFactory是Spring框架中的核心接口之一,它是用于管理和获取Bean实例的工厂。

具体来说,BeanFactory的作用主要有以下几个方面:

1. 实例化Bean:BeanFactory负责根据配置文件或注解等方式,实例化JavaBean。它会根据配置文件中的<bean>标签或注解中的配置信息,使用反射机制创建JavaBean的实例。通过BeanFactory,可以方便地创建和获取各种类型的Bean实例。

2. 管理Bean的生命周期:BeanFactory管理着Bean的生命周期。它会在需要时创建Bean的实例,并在不需要时销毁Bean的实例。通过BeanFactory,可以控制Bean的创建、初始化和销毁等过程,实现对Bean的灵活管理。

3. 注入依赖关系:BeanFactory负责将Bean之间的依赖关系注入到Bean实例中。它会根据配置文件中的<property>标签或注解中的依赖关系,将依赖的Bean注入到目标Bean中。通过BeanFactory,可以实现Bean之间的依赖注入,从而实现松耦合的设计。

4. 提供Bean的访问接口:BeanFactory提供了访问Bean的接口,可以方便地获取已经实例化的Bean。通过BeanFactory,可以根据Bean的名称或类型,获取到对应的Bean实例。这样可以方便地在应用程序中使用Bean,实现各种功能。

总之,BeanFactory是Spring框架中用于管理和获取Bean实例的核心接口。它负责实例化Bean、管理Bean的生命周期、注入依赖关系和提供Bean的访问接口等功能,是Spring框架中实现IoC(控制反转)和DI(依赖注入)的重要组成部分。

5 Aware

Aware是Spring框架中的一组接口,用于在Bean实例化过程中向Bean注入特定的资源或回调接口。

具体来说,Aware接口主要有以下几个作用:

1. 提供对Spring容器的访问:通过实现ApplicationContextAware接口,Bean可以获取对Spring容器的引用。这样可以在Bean中直接访问Spring容器的各种功能,如获取其他Bean、获取环境变量等。

2. 提供对BeanFactory的访问:通过实现BeanFactoryAware接口,Bean可以获取对BeanFactory的引用。这样可以在Bean中直接访问BeanFactory的各种功能,如获取Bean的定义、获取Bean的属性等。

3. 提供对Bean的名称的访问:通过实现BeanNameAware接口,Bean可以获取自己在Spring容器中的名称。这样可以在Bean中获取自己的名称,做一些特定的处理。

4. 提供对资源的访问:通过实现ResourceLoaderAware接口,Bean可以获取对资源加载器的引用。这样可以在Bean中直接加载资源,如读取配置文件、访问文件等。

5. 提供对消息源的访问:通过实现MessageSourceAware接口,Bean可以获取对消息源的引用。这样可以在Bean中直接访问消息源,实现国际化和本地化的功能。

通过实现这些Aware接口,Bean可以获取到Spring容器的相关资源或回调接口,从而实现对这些资源的访问或使用。这样可以在Bean中更方便地实现一些特定的功能,提高系统的灵活性和可扩展性。

 

三,Bean的单例与多例模式

       单例与多例模式对比


       单例的特点:节约资源,变量容易污染。

       多例的特点:占用大量资源,变量不易污染。

通过演示代码运行:

Spring使用单例模式的主要优点和好处包括:

1. 节省资源:单例模式可以确保在整个应用程序中只有一个实例存在,节省了系统资源的开销。每次请求都返回同一个实例,避免了重复创建对象的开销。

2. 提高性能:由于单例模式只创建一个实例,避免了频繁的创建和销毁对象的开销,从而提高了系统的性能。

3. 避免竞争条件:在多线程环境下,使用单例模式可以避免多个线程同时访问和修改对象的状态,从而避免了竞争条件和数据不一致的问题。

4. 统一管理和协调资源:单例模式可以统一管理和协调系统中的共享资源,确保资源的正确使用和释放,避免资源泄漏和浪费。

5. 提供全局访问点:单例模式可以提供一个全局的访问点,方便其他对象或模块通过该访问点来获取实例,简化了对象的使用和调用。

6. 简化配置和管理:在Spring框架中,将Bean定义为单例模式可以简化配置和管理,只需要在配置文件或注解中声明为单例即可,Spring容器负责创建和管理单例对象。

总的来说,Spring使用单例模式的优点包括节省资源、提高性能、避免竞争条件、统一管理和协调资源、提供全局访问点以及简化配置和管理。这些优点使得Spring在处理大规模应用和高并发环境下表现出色,并且提供了更好的可扩展性和可维护性。

 

在Spring框架中,多例模式(Prototype Pattern)是指每次获取对象实例时都会创建一个新的实例,相比于单例模式,多例模式具有以下优点和好处:

1. 灵活性:多例模式可以根据需求创建多个实例,每个实例可以有不同的状态和属性,提供了更大的灵活性和定制性。

2. 避免共享状态:多例模式每次创建新的实例,避免了多个对象之间共享状态的问题。每个实例都是独立的,互不影响。

3. 高并发性能:在高并发环境下,多例模式可以减少线程竞争,提高系统的并发性能。每个线程获取到的都是独立的实例,不会出现资源竞争的情况。

4. 避免单例模式的缺点:单例模式在某些场景下可能会存在线程安全问题、资源占用过多等缺点,而多例模式可以避免这些问题。

5. 降低耦合度:多例模式可以降低对象之间的耦合度,每个对象都是独立的,可以独立创建和销毁,不会产生过多的依赖关系。

6. 提供灵活的生命周期管理:多例模式可以通过Spring容器的生命周期管理功能来管理实例的创建和销毁,提供了更灵活的生命周期管理方式。

需要注意的是,多例模式也存在一些潜在的问题,比如对象的创建和销毁开销较大,可能会影响系统性能;多例模式可能会导致对象的过度创建,占用过多的系统资源。因此,在使用多例模式时需要根据具体的业务场景和性能需求进行权衡和选择。

 

1.spring.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="paramAction" class="com.zking.beanLife.ParamAction" scope="prototype">
        <constructor-arg name="name" value="牛妈肥镖"></constructor-arg>
        <constructor-arg name="age" value="21"></constructor-arg>
        <constructor-arg name="hobby">
            <list>
                <value>抽烟</value>
                <value>玩及</value>
                <value>彩笔</value>
            </list>
        </constructor-arg>
    </bean>
    <bean id="instanceFactory" class="com.zking.beanLife.InstanceFactory"
          scope="prototype" init-method="init" destroy-method="destroy"></bean>
</beans>

2.Demo测试类

package com.zking.beanLife;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/*
 * spring bean的生命週期
 * spring bean的單例多例
 */
public class Demo2 {
  // 体现单例与多例的区别
  @Test
  public void test1() {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring.xml");
//    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-context.xml");
    ParamAction p1 = (ParamAction) applicationContext.getBean("paramAction");
    ParamAction p2 = (ParamAction) applicationContext.getBean("paramAction");
     System.out.println(p1==p2);
    p1.execute();
    p2.execute();
//    单例时,容器销毁instanceFactory对象也销毁;多例时,容器销毁对象不一定销毁;
    applicationContext.close();
  }
  // 体现单例与多例的初始化的时间点 instanceFactory
  @Test
  public void test2() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring.xml");
  }
  // BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式
  // 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化
  @Test
  public void test3() {
    // ClassPathXmlApplicationContext applicationContext = new
    // ClassPathXmlApplicationContext("/spring-context.xml");
    Resource resource = new ClassPathResource("/spring.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);
//    InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
  }
}

这里单例模式改成多例模式只要在spring.xml中指定即可

演示效果:

单例模式运行结果:

多例模式运行结果:

3.单例模式和多例模式的适用场景

单例模式和多例模式在不同的场景下具有不同的适用性。以下是它们常见的适用场景:

适用于单例模式的场景:

资源共享:当需要在应用程序的多个组件之间共享同一份资源或数据时,单例模式可以确保全局范围内的数据一致性。

工厂类:当需要创建一个全局工厂类来统一管理对象的创建和生命周期时,单例模式可以确保该工厂类始终只有一个实例。

配置信息:当需要在应用程序中加载一份全局的配置信息,并且多个组件需要共享该配置信息时,单例模式可以确保配置信息的一致性和高效访问。

日志记录器:当需要在整个应用程序中使用同一个日志记录器来记录日志时,单例模式可以确保日志的一致性和集中管理。

适用于多例模式的场景:

并发请求处理:当需要在多线程或并发环境下处理请求,并且每个请求使用独立的实例来保证状态隔离时,多例模式可以为每个请求创建一个独立的对象。

对象池:当需要管理一组可复用的对象,并且对象在不同的时刻需要创建和销毁时,多例模式可以提供对象池来管理对象的生命周期,以减少创建和销毁的开销。

状态管理:当对象的状态需要在不同的上下文环境中独立维护和处理时,多例模式可以为每个上下文环境创建一个独立的实例,以避免状态冲突和相互干扰。

服务提供者:当系统需要支持多个相同类型的服务提供者,并且每个服务提供者需要独立的实例时,多例模式可以满足服务提供者的创建和管理需求。

 

总结:

Spring框架的生命周期主要包括创建、初始化和销毁三个阶段。通过容器管理Bean的生命周期,可以自定义Bean的初始化和销毁方法,在特定的时间点由容器来调用。单实例Bean的整个生命周期都可以进行控制。Spring Bean的生命周期分为四个阶段和多个扩展点。扩展点可以影响多个Bean或单个Bean的生命周期。总之,Spring框架提供了灵活的生命周期管理机制,使得开发者能够更好地控制和定制Bean的创建和销毁过程

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
19天前
|
XML 安全 Java
|
2天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
17 6
|
4天前
|
XML Java 数据格式
🌱 深入Spring的心脏:Bean配置的艺术与实践 🌟
本文深入探讨了Spring框架中Bean配置的奥秘,从基本概念到XML配置文件的使用,再到静态工厂方式实例化Bean的详细步骤,通过实际代码示例帮助读者更好地理解和应用Spring的Bean配置。希望对你的Spring开发之旅有所助益。
29 3
|
1月前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
17天前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
27 1
|
2月前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
80 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
3月前
|
缓存 安全 Java
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
从底层源码入手,通过代码示例,追踪AnnotationConfigApplicationContext加载配置类、启动Spring容器的整个流程,并对IOC、BeanDefinition、PostProcesser等相关概念进行解释
315 24
Spring框架中Bean是如何加载的?从底层源码入手,详细解读Bean的创建流程
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
3月前
|
XML Java 数据格式
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
Spring 第二节内容补充 关于Bean配置的更多内容和细节 万字详解!
247 18
Spring IOC—基于XML配置Bean的更多内容和细节(通俗易懂)
|
3月前
|
XML Java 数据格式
spring复习02,xml配置管理bean
详细讲解了Spring框架中基于XML配置文件管理bean的各种方式,包括获取bean、依赖注入、特殊值处理、属性赋值、集合类型处理、p命名空间、bean作用域及生命周期和自动装配。
spring复习02,xml配置管理bean
下一篇
DataWorks