”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > Singleton 和原型 Spring Bean 范围:详细探索

Singleton 和原型 Spring Bean 范围:详细探索

发布于2024-11-06
浏览:704

Singleton and Prototype Spring Bean Scopes: A Detailed Exploration

当我第一次开始使用 Spring 时,最让我感兴趣的概念之一是 bean 范围的想法。 Spring 提供了各种 bean 作用域,用于确定在 Spring 容器内创建的 bean 的生命周期。最常用的两个范围是 Singleton 和 Prototype。了解这些范围对于设计高效且有效的 Spring 应用程序至关重要,所以让我带您了解我对它们的了解。

了解 Spring Bean 范围

在Spring中,bean是一个由Spring IoC(控制反转)容器实例化、组装和管理的对象。 Bean 作用域是指 bean 的生命周期 - 创建 bean 实例的方式和时间,以及它们的持续时间。

Spring 提供了几个 bean 作用域,但我将重点关注的两个是:

  • 单例作用域
  • 原型范围

每个范围都有其特定的用例,选择正确的范围可以显着影响应用程序的行为和性能。

单例范围

Singleton 作用域是 Spring 中的默认作用域,也是我最常使用的作用域。当使用 Singleton 范围定义一个 bean 时,这意味着 Spring 容器将仅创建该 bean 的一个实例,并且该单个实例将在整个应用程序上下文中共享。

它是如何运作的

当我将一个 bean 声明为 Singleton 时,Spring 在第一次请求时(在应用程序上下文启动期间或首次引用它时)创建该 bean 实例。之后,对该 bean 的每个后续请求都将返回相同的实例。

这是一个简单的例子:

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyService();
    }
}

在此示例中,myService() 是一个 Singleton bean。每次我从 Spring 上下文请求 MyService bean 时,我都会得到相同的实例。

Singleton Bean 的用例

我发现 Singleton 作用域非常适合无状态 Bean——那些不保存任何客户端特定信息的 Bean。示例包括:

  • 服务类:通常,这些类包含可以在应用程序之间共享的业务逻辑,而不需要单独的实例。
  • DAO 类:由于它们通常与数据库交互并且不维护特定于客户端的状态,因此单个实​​例就足够了。

优点和注意事项

Singleton beans 的主要优点是内存效率。通过重用单个实例,应用程序消耗更少的内存,并且创建和销毁对象的开销最小化。然而,对维护状态的 Singleton beans 保持谨慎是很重要的。如果 Singleton bean 无意中保存了状态(例如实例变量),则该状态可以在多个客户端之间共享,从而导致潜在的数据不一致。

原型范围

与 Singleton 相比,Prototype 范围在每次从 Spring 容器请求 bean 时都会创建一个新的 bean 实例。当我了解到这一点时,很明显 Prototype beans 对于每次使用都需要一个新实例的场景非常有用。

它是如何运作的

当使用 Prototype 作用域定义 bean 时,每次请求该 bean 时 Spring 都会返回一个新实例。以下是我定义 Prototype bean 的方式:

@Configuration
public class AppConfig {
    @Bean
    @Scope("prototype")
    public MyService myService() {
        return new MyService();
    }
}

在此示例中,每次我从 Spring 上下文请求 MyService bean 时,Spring 都会创建 MyService 的一个新实例。

原型 Bean 的用例

原型 bean 在处理有状态 bean 时特别有用——那些维护某种特定于客户端的状态或每次使用都需要唯一配置的 bean。一些典型的用例包括:

  • 命令对象:如果我要实现像 Command 这样的模式,其中每个命令单独执行并维护自己的状态,那么 Prototype bean 是正确的选择。
  • 会话或请求范围 Beans:在 Web 应用程序中,特定于用户会话或请求的 Bean 可以定义为原型,以确保为每个用户或请求创建一个新实例。

优点和注意事项

使用 Prototype beans 的主要优点是它在创建新实例时提供的灵活性。这在处理有状态对象时特别有用。然而,在性能和资源使用方面需要权衡。由于每次都会创建一个新实例,因此可能会导致更高的内存消耗和更频繁的垃圾收集。此外,与 Singleton bean 不同,Spring 不管理 Prototype bean 除了创建之外的生命周期,因此我必须手动处理这些 bean 的销毁和清理。

单例与原型:选择正确的范围

设计 Spring 应用程序时我面临的关键决策之一是在 Singleton 和 Prototype 范围之间进行选择。以下是我考虑的因素的总结:

  • 有状态:如果bean是无状态的,Singleton通常是最好的选择。对于有状态bean,Prototype 更合适。
  • 资源管理:单例 bean 的内存效率更高,因为只维护一个实例。原型 Bean 在提供更大灵活性的同时,也消耗更多资源。
  • 生命周期管理:单例 bean 在其整个生命周期中由 Spring 容器进行管理。相反,我必须管理 Prototype beans 的整个生命周期。

实际例子

让我提供一个实际场景,可能有助于阐明何时使用每个范围。假设我正在构建一个在线购物应用程序。

  • 购物车服务:该服务通常是无状态的,并且是 Singleton bean 的良好候选者。无需每次都创建新实例,同一个服务可以处理多个请求。
  • 订单处理:另一方面,代表客户订单的 Order 对象是有状态的,包含特定于该订单的详细信息。因此,它应该是一个 Prototype bean,以便每个订单都由 Order 类的单独实例处理。

混合范围:注意事项

我从惨痛的教训中学到的一件事是,混合使用 Singleton 和 Prototype beans 可能会导致意想不到的问题。例如,将 Prototype 范围的 bean 注入到 Singleton bean 中可能会导致 Singleton bean 始终使用 Prototype bean 的同一实例。为了避免这种情况,我通常注入一个 Provider 或使用 @Lookup 注释来确保每次需要时都会创建 Prototype bean 的新实例。

@Service
public class SingletonService {

    @Autowired
    private Provider myPrototypeServiceProvider;

    public void usePrototypeService() {
        MyPrototypeService prototypeService = myPrototypeServiceProvider.get();
        prototypeService.execute();
    }
}

在此示例中,myPrototypeServiceProvider.get() 确保每次在 Singleton bean 中调用时都会创建 MyPrototypeService 的新实例。

再见 !

理解 Spring 中的 Singleton 和 Prototype bean 范围的细微差别对于我作为开发人员的旅程至关重要。根据用例,这两种示波器都具有明显的优势,选择正确的示波器可以显着影响应用程序的性能和设计。

根据我的经验,Singleton 由于其效率和简单性而成为大多数 bean 的首选范围,而 Prototype 则保留给那些每次都需要新实例的特殊情况。通过仔细考虑 bean 的有状态性以及它们在应用程序中的使用方式,我可以做出明智的决策,从而构建更好、更易于维护的 Spring 应用程序。

版本声明 本文转载于:https://dev.to/isaactony/singleton-and-prototype-spring-bean-scopes-a-detailed-exploration-1gpl?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 解决MySQL插入Emoji时出现的\\"字符串值错误\\"异常
    解决MySQL插入Emoji时出现的\\"字符串值错误\\"异常
    Resolving Incorrect String Value Exception When Inserting EmojiWhen attempting to insert a string containing emoji characters into a MySQL database us...
    编程 发布于2025-07-16
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法表示的字符串时,您可能会遇到错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && ...
    编程 发布于2025-07-16
  • 为什么使用Firefox后退按钮时JavaScript执行停止?
    为什么使用Firefox后退按钮时JavaScript执行停止?
    导航历史记录问题:JavaScript使用Firefox Back Back 此行为是由浏览器缓存JavaScript资源引起的。要解决此问题并确保在后续页面访问中执行脚本,Firefox用户应设置一个空功能。 警报'); }; alert('inline Alert')...
    编程 发布于2025-07-16
  • Java是否允许多种返回类型:仔细研究通用方法?
    Java是否允许多种返回类型:仔细研究通用方法?
    在Java中的多个返回类型:一种误解类型:在Java编程中揭示,在Java编程中,Peculiar方法签名可能会出现,可能会出现,使开发人员陷入困境,使开发人员陷入困境。 getResult(string s); ,其中foo是自定义类。该方法声明似乎拥有两种返回类型:列表和E。但这确实是如此吗...
    编程 发布于2025-07-16
  • 如何在GO编译器中自定义编译优化?
    如何在GO编译器中自定义编译优化?
    在GO编译器中自定义编译优化 GO中的默认编译过程遵循特定的优化策略。 However, users may need to adjust these optimizations for specific requirements.Optimization Control in Go Compi...
    编程 发布于2025-07-16
  • Java中Lambda表达式为何需要“final”或“有效final”变量?
    Java中Lambda表达式为何需要“final”或“有效final”变量?
    Lambda Expressions Require "Final" or "Effectively Final" VariablesThe error message "Variable used in lambda expression shou...
    编程 发布于2025-07-16
  • 为什么我会收到MySQL错误#1089:错误的前缀密钥?
    为什么我会收到MySQL错误#1089:错误的前缀密钥?
    mySQL错误#1089:错误的前缀键错误descript [#1089-不正确的前缀键在尝试在表中创建一个prefix键时会出现。前缀键旨在索引字符串列的特定前缀长度长度,可以更快地搜索这些前缀。了解prefix keys `这将在整个Movie_ID列上创建标准主键。主密钥对于唯一识别...
    编程 发布于2025-07-16
  • Python环境变量的访问与管理方法
    Python环境变量的访问与管理方法
    Accessing Environment Variables in PythonTo access environment variables in Python, utilize the os.environ object, which represents a mapping of envir...
    编程 发布于2025-07-16
  • 如何使用Java.net.urlConnection和Multipart/form-data编码使用其他参数上传文件?
    如何使用Java.net.urlConnection和Multipart/form-data编码使用其他参数上传文件?
    使用http request 上传文件上传到http server,同时也提交其他参数,java.net.net.urlconnection and Multipart/form-data Encoding是普遍的。 Here's a breakdown of the process:Mu...
    编程 发布于2025-07-16
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-07-16
  • Python元类工作原理及类创建与定制
    Python元类工作原理及类创建与定制
    python中的metaclasses是什么? Metaclasses负责在Python中创建类对象。就像类创建实例一样,元类也创建类。他们提供了对类创建过程的控制层,允许自定义类行为和属性。在Python中理解类作为对象的概念,类是描述用于创建新实例或对象的蓝图的对象。这意味着类本身是使用类关...
    编程 发布于2025-07-16
  • 如何干净地删除匿名JavaScript事件处理程序?
    如何干净地删除匿名JavaScript事件处理程序?
    删除匿名事件侦听器将匿名事件侦听器添加到元素中会提供灵活性和简单性,但是当要删除它们时,可以构成挑战,而无需替换元素本身就可以替换一个问题。 element? element.addeventlistener(event,function(){/在这里工作/},false); 要解决此问题,请考虑...
    编程 发布于2025-07-16
  • 在Python中如何创建动态变量?
    在Python中如何创建动态变量?
    在Python 中,动态创建变量的功能可以是一种强大的工具,尤其是在使用复杂的数据结构或算法时,Dynamic Variable Creation的动态变量创建。 Python提供了几种创造性的方法来实现这一目标。利用dictionaries 一种有效的方法是利用字典。字典允许您动态创建密钥并分...
    编程 发布于2025-07-16
  • Go语言如何动态发现导出包类型?
    Go语言如何动态发现导出包类型?
    与反射软件包中的有限类型的发现能力相反,本文探讨了在运行时发现所有包装类型(尤其是struntime go import( “ FMT” “去/进口商” ) func main(){ pkg,err:= incorter.default()。导入(“ time”) ...
    编程 发布于2025-07-16
  • 在C#中如何高效重复字符串字符用于缩进?
    在C#中如何高效重复字符串字符用于缩进?
    在基于项目的深度下固定字符串时,重复一个字符串以进行凹痕,很方便有效地有一种有效的方法来返回字符串重复指定的次数的字符串。使用指定的次数。 constructor 这将返回字符串“ -----”。 字符串凹痕= new String(' - ',depth); console.Wr...
    编程 发布于2025-07-16

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3