Spring的生命周期及Spring Bean单例和多例---超详细教学

简介: Spring的生命周期及Spring Bean单例和多例---超详细教学

一,何为spring生命周期    

   一个Bean对象从被Spring容器创建到被销毁的整个过程。Spring框架对Bean对象的生命周期进行了管理,提供了灵活性和控制权,让开发人员能够在不同的阶段进行自定义操作

1.1生命周期图

1.2.为什么要学习对象的生命周期?

1.2.1 定位和解决问题

    对象的生命周期可以帮助我们准确定位和解决程序中的问题。当程序出现 bug 或异常时,了解对象的生命周期可以帮助我们追踪问题所在,并在适当的阶段进行调试和修复。

1.2.2 资源管理

   对象的生命周期涉及到资源的分配和释放,如内存、数据库连接、文件等。了解对象的生命周期可以帮助我们更好地管理和优化资源的使用,避免资源泄漏或过度占用资源的情况发生。

1.2.3 性能优化

  了解对象的生命周期可以帮助我们优化程序的性能。通过有效地管理对象的创建和销毁,以及合理利用对象池、缓存等技术,可以减少不必要的资源消耗和提高程序的运行效率。

1.2.4 设计模式和架构

  对象的生命周期与设计模式和架构密切相关。学习对象的生命周期可以帮助我们更好地设计和实现面向对象的系统,选择合适的设计模式和架构来管理和组织对象,以实现可维护、可扩展和高效的系统

1.2.5 对象的状态管理

    对象的生命周期涉及到对象的状态转换和行为变化。了解对象的生命周期可以帮助我们更好地管理对象的状态,避免状态混乱或不一致的情况发生,以确保程序的正确性和可靠性

1.3 生命周期大致流程

1. Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化

2. Bean实例化后将Bean的引入和值注入到Bean的属性中

3. 如果Bean实现了BeanNameAware接口的话,Spring将Bean的id传递给setBeanName()方法
BeanNameAware的作用:让Bean获取自己在BeanFactory配置中的名字。

4. 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
BeanFactoryAware的作用:让Bean获取配置他们的BeanFactory的引用。

5. 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入
为什么使用ApplicationContextAware接口:在spring项目中,类之间的关系是spring容器来管理的,但是一个项目中有些类不受spring容器管理缺需要使用受spring管理的bean,这时候不能通过正常的方式注入bean,这时候spring给我们提供了ApplicationContextAware接口,我们可以编写一个工具类来实现ApplicationContextAware,通过工具类来获取我们需要的bean然后供不在spring容器中的类调用。

6. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()方法
postProcessBeforeInitialization()方法:初始化方法之前调用

7. 如果Bean实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
afterPropertiesSet()方法:初始化方法。如果使用了init-method声明了初始化方法,则执行顺序为:先执行afterPropertiesSet()方法,再执行init-method声明的方法。

8. 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法
postProcessAfterInitialization()方法:初始化方法之后调用

9. 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁

10. 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用
destory()方法:销毁前调用。如果使用了destory-method声明了销毁方法,则执行顺序为:先执行destory()方法,再执行destory-method声明的方法。

二, Spring Bean的单例与多例的作用域

2.1 单例模式(Singleton):

  • 单例是指在整个应用程序上下文中只创建一个实例,并且所有的请求都会返回同一个实例
  • 默认情况下,Spring容器中的Bean都是单例的
  • 单例模式适用于那些不需要维护状态的Bean,或者对资源消耗较大的Bean进行共享

缺点:使用单例会有变量污染,单例是根据spring上下文初始化;容器生对象生,容器死对象死

2.2 多例模式(Prototype):

  • 多例是指每次请求时都会创建一个新的实例,每个实例都是独立的
  • 每次从容器中获取该Bean时,都会创建一个新的实例
  • 多例模式适用于那些需要维护状态的Bean,或者对资源消耗较小的Bean进行独立创建

缺点:使用多例及其消耗内存,多例使用时候才会创建,销毁跟着jvm走。

三  单例Bean与多例Bean的配置方式(两种)

3.1 注解方式:

// 使用注解配置单例Bean
@Component
@Scope("singleton")
public class MySingletonBean {
    // ...
}
// 使用注解配置多例Bean
@Component
@Scope("prototype")
public class MyPrototypeBean {
    // ...
}

3.2  XML方式:

<!-- 使用XML配置单例Bean -->
    <bean id="paramAction" class="com.zking.beanlife.ParamAction" scope="singleton">
    <!-- ... -->
</bean>
<!-- 使用XML配置多例Bean -->
  <bean id="paramAction" class="com.zking.beanlife.ParamAction" scope="prototype">
    <!-- ... -->
</bean>

单例案例:

定义一个类,并创建三个方法

package com.zking.beanlife;
public class InstanceFactory {
  public void init() {
    System.out.println("初始化方法");
  }
  public void destroy() {
    System.out.println("销毁方法");
  }
  public void service() {
    System.out.println("业务方法");
  }
}

后端Servlet

package com.zking.beanlife;
import java.util.List;
public class ParamAction {
  private int age;
  private String name;
  private List<String> hobby;
  private int num = 1;
  // private UserBiz userBiz = new UserBizImpl1();
  public ParamAction() {
    super();
  }
  public ParamAction(int age, String name, List<String> hobby) {
    super();
    this.age = age;
    this.name = name;
    this.hobby = hobby;
  }
  public void execute() {
    // userBiz.upload();
    // userBiz = new UserBizImpl2();
    System.out.println("this.num=" + this.num++);
    System.out.println(this.name);
    System.out.println(this.age);
    System.out.println(this.hobby);
  }
}

 

测试类:

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-context.xml");
//    InstanceFactory   instanceFactory = (InstanceFactory) applicationContext.getBean("instanceFactory");
    //    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-context.xml");
  }
  // BeanFactory会初始化bean对象,但会根据不同的实现子类采取不同的初始化方式
  // 默认情况下bean的初始化,单例模式立马会执行,但是此时XmlBeanFactory作为子类,单例模式下容器创建,bean依赖没有初始化,只有要获取使用bean对象才进行初始化
  @Test
  public void test3() {
    // ClassPathXmlApplicationContext applicationContext = new
    // ClassPathXmlApplicationContext("/spring-context.xml");
    Resource resource = new ClassPathResource("/spring-context.xml");
    BeanFactory beanFactory = new XmlBeanFactory(resource);
//    InstanceFactory i1 = (InstanceFactory) beanFactory.getBean("instanceFactory");
  }
}

spring Config文件的配置

 

运行结果:

 

这里的num值分别为1和2,则说明是单例的,单例模式即存在变量污染

多例案例:

 

运行结果:

多例使用时候才会创建,销毁跟着jvm走

目录
相关文章
|
19天前
|
XML 安全 Java
|
2天前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
17 6
|
3天前
|
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的一些子标签及注解的使用)
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
2月前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
135 1
|
2月前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
51 1
|
6月前
|
Java 开发者 Spring
解析Spring中Bean的生命周期
解析Spring中Bean的生命周期
60 2
下一篇
DataWorks