一、前言
前面写过一篇博客,是关于Ioc控制反转的。
那篇文中,主要介绍了Ioc思想及其常见实现方式——依赖注入(DI),然后演示了 Microsoft.Extensions.DependencyInjection 的使用(这个应该算.NET自带的DI包)。
不过DI的使用上,只是简单演示流程,并未进行深入学习。本文就DI中的 服务生命周期(ServiceLifetime) 进一步学习。
二、服务生命周期
2.1 服务生命周期
为什么会从服务生命周期学起呢?
因为我往服务集(ServiceCollection)中添加元素时,发现有三种方法:
AddScoped()、AddSingleton()、AddTransient()。
分别表示范围的/作用域的、单例的、瞬时的,而这三种方法对应ServiceLifetime枚举中的三个字段。
public enum ServiceLifetime
{
//
// 摘要:
// 将服务创建为单例
Singleton,
//
// 摘要:
// 为每个作用域创建新的服务实例
//
// 言论:
// In ASP.NET Core applications a scope is created around each server request.
Scoped,
//
// 摘要:
// 每次都会创建一个新实例
// // requested.
Transient
}
- Singleton:
- 对象在整个应用程序生命周期中只被创建一次,所有请求都共享这个实例。适用于全局共享的资源或服务,如配置、缓存等。 Scoped:
- 在同一个作用域内,对象只会被创建一次,所有请求都共享这个实例。当作用域结束时,对象会被销毁。适用于需要在一个请求周期内共享状态的场景。 Transient:
- 每次请求都会创建一个新的对象实例,不同请求之间相互独立。适用于无状态的服务或短暂的对象。
这些策略有助于控制资源的使用和提高应用程序的性能。
2.2 状态
这里的“状态”指的是。状态可以是对象的属性或字段值,用于描述对象在某个特定时间点的状况。有状态的对象在其生命周期内会发生变化,而无状态的对象则在整个生命周期内保持不变。在依赖注入的上下文中,选择合适的生命周期管理策略(Scoped、Singleton、Transient)可以确保对象在其生命周期内正确地维护其状态。
2.3 拓展:静态类和单例的应用场景
说到状态,再进一步拓展一下。
上面说了无状态对象在整个生命周期内保持不变。一个典型的例子就是一个计算器类。计算器类可以包含一些用于执行基本数学运算(如:加减乘除)的方法,但它不会存储任何与这些操作相关的数据。每次调用计算器方法时,只需根据传入的参数执行相应的计算并返回结果,而不需要保持或修改任何内部状态(当然,也有有历史记录的计算器,计算后会修改其状态,但这边不讨论该情况)。因此,计算器类是无状态的,可以在多个请求之间共享和重用,而不会产生副作用或竞争条件。
对于无状态类,可以使用静态类或单例模式,具体取决于你的需求和设计目标。
- 静态类(static class):
- 静态类中的方法和属性都是静态的,这意味着你无需创建类的实例就可以直接访问它们。静态类适用于不需要维护状态的实用程序方法或功能,如数学计算、字符串操作等。静态类的静态成员只会被创建和初始化一次,然后在整个应用程序中共享,因此在内存占用方面较为节省。 单例模式:
- 单例模式确保一个类在程序中仅有一个实例,并提供一个全局访问点。它适用于需要维护状态但状态可在整个应用程序中共享的情况。虽然单例模式也可用于无状态类,但通常静态类更为简单、高效。
对于无状态类,静态类通常是更好的选择,因为它们简单、高效且易于使用。
三、总结
在Ioc中,
- Singleton用于在整个应用程序生命周期中只创建一次,每次请求都是同一个实例的情况;
- Scoped用于同一作用域内只被创建一次;
- Transient每次请求都是一个新的实例;
- 状态是对象在其生命周期内保持和维护的数据或信息;
- 无状态类往往用静态类实现。