掌握 Spring IoC 容器与 Bean 作用域:详解 singleton 与 prototype 的使用与配置

本文涉及的产品
性能测试 PTS,5000VUM额度
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
可观测监控 Prometheus 版,每月50GB免费额度
简介: 在您的应用程序中,由 Spring IoC 容器管理的形成其核心的对象被称为 "bean"。一个 bean 是由 Spring IoC 容器实例化、组装和管理的对象

在您的应用程序中,由 Spring IoC 容器管理的形成其核心的对象被称为 "bean"。一个 bean 是由 Spring IoC 容器实例化、组装和管理的对象

这些 bean 是通过您提供给容器的配置元数据创建的。Bean 定义包含了所谓的配置元数据,容器需要了解以下内容:

  • 如何创建一个 bean
  • Bean 的生命周期详细信息
  • Bean 的依赖关系

上述所有的配置元数据都转化为每个 bean 定义的以下属性集合。

序号 属性和描述
1 class
这是必填属性,指定要用于创建 beanbean 类。
2 name
此属性唯一地指定 bean 标识符。在基于 XML 的配置元数据中,您可以使用 id 和/或 name 属性来指定 bean 标识符。
3 scope
此属性指定从特定 bean 定义创建的对象的范围
4 constructor-arg
这用于注入依赖项
5 properties
这用于注入依赖项
6 autowiring mode
这用于注入依赖项
7 lazy-initialization mode
延迟初始化的 bean 告诉 IoC 容器在首次请求时创建 bean 实例,而不是在启动时创建。
8 initialization method
在容器设置了 bean 的所有必需属性之后,要调用的回调函数
9 destruction method
在包含 bean 的容器销毁时要使用的回调函数

Spring 配置元数据

Spring IoC 容器与实际编写配置元数据的格式完全解耦。以下是向 Spring 容器提供配置元数据的三种重要方法:

  • 基于 XML 的配置文件。
  • 基于注解的配置。
  • 基于 Java 的配置。

您已经看到了如何将基于 XML 的配置元数据提供给容器,但让我们看一下包含不同 bean 定义的 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-3.0.xsd">

   <!-- 一个简单的 `bean` 定义 -->
   <bean id = "..." class = "...">
      <!-- 此处是该 `bean` 的协作者和配置 -->
   </bean>

   <!-- 启用延迟初始化的 `bean` 定义 -->
   <bean id = "..." class = "..." lazy-init = "true">
      <!-- 此处是该 `bean` 的协作者和配置 -->
   </bean>

   <!-- 具有初始化方法的 `bean` 定义 -->
   <bean id = "..." class = "..." init-method = "...">
      <!-- 此处是该 `bean` 的协作者和配置 -->
   </bean>

   <!-- 具有销毁方法的 `bean` 定义 -->
   <bean id = "..." class = "..." destroy-method = "...">
      <!-- 此处是该 `bean` 的协作者和配置 -->
   </bean>

   <!-- 更多的 `bean` 定义在此处 -->

Spring 中的 Bean 作用域

在定义 <bean> 时,您可以选择为该 bean 声明一个作用域。例如,要强制 Spring 每次需要时生成新的 bean 实例,您应该将 bean 的作用域属性声明为 prototype。类似地,如果您希望 Spring 每次需要时返回相同的 bean 实例,您应该将 bean 的作用域属性声明为 singleton

Spring 框架支持以下五种作用域,其中三种仅在使用与 Web 相关的 ApplicationContext 时才可用。

序号 作用域 & 描述
1 singleton
bean 定义的作用域限制为 Spring IoC 容器中的单个实例(默认)。
2 prototype
将单个 bean 定义的作用域限制为具有任意数量的对象实例。
3 request
bean 定义的作用域限制为 HTTP 请求。仅在具有与 Web 相关的 Spring ApplicationContext 的情况下有效。
4 session
bean 定义的作用域限制为 HTTP 会话。仅在具有与 Web 相关的 Spring ApplicationContext 的情况下有效。
5 global-session
bean 定义的作用域限制为全局 HTTP 会话。仅在具有与 Web 相关的 Spring ApplicationContext 的情况下有效。

当讨论与

Web 相关的 Spring ApplicationContext 时,将讨论其他三种作用域。

单例作用域(singleton

如果将作用域设置为 singletonSpring IoC 容器将创建一个对象的确切实例,该实例由 bean 定义定义。此单个实例存储在此类单例 bean 的缓存中,对于该命名 bean 的所有后续请求和引用都会返回缓存的对象。

默认作用域始终是 singleton。但是,当您需要一个且仅一个 bean 实例时,您可以在 bean 配置文件中将作用域属性设置为 singleton,如下所示:

<!-- 具有 `singleton` 作用域的 `bean` 定义 -->
<bean id="..." class="..." scope="singleton">
   <!-- 此处放置此 `bean` 的协作者和配置 -->

示例

假设您已经准备好 Eclipse IDE,并采取以下步骤创建 Spring 应用程序:

步骤

  1. 创建一个名为 SpringExample 的项目,在创建的项目中的 src 文件夹下创建一个名为 com.tutorialspoint 的包
  2. 使用"Add External JARs"选项添加所需的 Spring
  3. com.tutorialspoint 包下创建 JavaHelloWorldMainApp
  4. src 文件夹下创建 Beans 配置文件 Beans.xml
  5. 最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按以下说明运行应用程序。

以下是 HelloWorld.java 文件的内容:

package com.tutorialspoint;

public class HelloWorld {
   
   private String message;

   public void setMessage(String message){
   
      this.message  = message;
   }
   public void getMessage(){
   
      System.out.println("Your Message : " + message);
   }
}

以下是 MainApp.java 文件的内容:

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   
   public static void main(String[] args) {
   
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.setMessage("I'm object A");
      objA.getMessage();

      HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
      objB.getMessage();
   }
}

以下是 singleton 作用域所需的 Beans.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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" scope="singleton">
   </bean>

</beans>

当您完成创建源代码和 bean 配置文件后,让我们运行应用程序。如果您的应用程序一切正常,它将打印以下消息:

Your Message : I'm object A
Your Message : I'm object A

原型作用域(prototype

如果将作用域设置为 prototypeSpring IoC 容器将在每次请求特定 bean 时创建该对象的新 bean 实例。通常,对于所有有状态的 bean,使用 prototype 作用域,对于无状态的 bean,使用 singleton 作用域。

要定义原型作用域,您可以在 bean 配置文件中将作用域属性设置为 prototype,如下所示:

<!-- 具有 `prototype` 作用域的 `bean` 定义 -->
<bean id="..." class="..." scope="prototype">
   <!-- 此处放置此 `bean` 的协作者和配置 -->
</bean>

示例

假设您已经准备好 Eclipse IDE,并采取以下步骤创建 Spring 应用程序:

步骤

  1. 创建一个名为 SpringExample 的项目,在创建的项目中的 src 文件夹下创建一个名为 com.tutorialspoint 的包
  2. 使用"Add External JARs"选项添加所需的 Spring
  3. com.tutorialspoint 包下创建 JavaHelloWorldMainApp
  4. src 文件夹下创建 Beans 配置文件 Beans.xml
  5. 最后一步是创建所有 Java 文件和 Bean 配置文件的内容,并按以下说明运行应用程序。

以下是 HelloWorld.java 文件的内容:

package com.tutorialspoint;

public class HelloWorld {
   
   private String message;

   public void setMessage(String message){
   
      this.message  = message;
   }
   public void getMessage(){
   
      System.out.println("Your Message : " + message);
   }
}

以下是 MainApp.java 文件的内容:

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   
   public static void main(String[] args) {
   
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.setMessage("I'm object A");
      objA.getMessage();

      HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
      objB.getMessage();
   }
}

以下是 prototype 作用域所需的 Beans.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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" scope="prototype">
   </bean>

</beans>

当您完成创建源代码和bean配置文件后,让我们运行应用程序。如果您的应用程序一切正常,它将打印以下消息:

Your Message : I'm object A
Your Message : I'm object A

最后

为了方便其他设备和平台的小伙伴观看往期文章:

微信公众号搜索:Let us Coding,关注后即可获取最新文章推送

看完如果觉得有帮助,欢迎 点赞、收藏、关注

相关文章
|
1月前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
2月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
20天前
|
Kubernetes 监控 Java
如何在Kubernetes中配置镜像和容器的定期垃圾回收
如何在Kubernetes中配置镜像和容器的定期垃圾回收
|
23天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
31 0
|
2月前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
73 0
|
2月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
50 0
|
18天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
61 2
|
8天前
|
Kubernetes Linux 开发者
深入探索容器化技术——Docker 的实战应用
深入探索容器化技术——Docker 的实战应用
39 5
|
12天前
|
运维 Cloud Native 云计算
云原生之旅:Docker容器化实战
本文将带你走进云原生的世界,深入理解Docker技术如何改变应用部署与运维。我们将通过实际案例,展示如何利用Docker简化开发流程,提升应用的可移植性和伸缩性。文章不仅介绍基础概念,还提供操作指南和最佳实践,帮助你快速上手Docker,开启云原生的第一步。
|
15天前
|
机器学习/深度学习 数据采集 Docker
Docker容器化实战:构建并部署一个简单的Web应用
Docker容器化实战:构建并部署一个简单的Web应用