一、依赖注入 (DI) 定义
依赖注入(Dependency Injection,简称DI)是一种设计模式,用于解耦组件(服务)之间的依赖关系。它通过将依赖关系的创建和管理交给外部容器来实现,而不是在组件(服务)内部直接创建依赖对象。
它可以帮助我们更好地管理和组织组件,提高代码的可读性,扩展性和可测试性。
通过 IServiceCollection 和 IServiceProvider 来实现的,他们直接被收入到了runtime libraries,在整个.NET平台下通用。
ServiceProvider:
ServiceProvider(依赖注入容器)不仅对外提供GetService()、GetRequiredService()方法,还可以方便地注册和管理应用程序需要的各种服务。
通过创建ServiceProvider的方式,我们可以更好地理解管理和控制服务实例的生命周期和依赖关系。
-
应用程序级别的根级ServiceProvider
.NET Core应用程序通常会使用一个应用程序级别的根级ServiceProvider,它是全局唯一的,并且负责维护所有单例服务的实例。这个实例通常是由WebHostBuilder、HostBuilder或ServiceCollection等类创建和配置的,可以通过IServiceProvider接口来访问。 -
每个请求的作用域级别的ServiceProvider
除了根级ServiceProvider之外,在.NET Core中还可以创建每个请求的作用域级别的ServiceProvider,它通常用于管理Scoped和Transient服务的生命周期和依赖关系。每个作用域级别的ServiceProvider都有自己独立的作用域,可以通过IServiceScopeFactory创建,同时也继承了根级ServiceProvider中注册的所有单例服务的实例。 -
自定义级别的ServiceProvider
在某些情况下,我们可能需要自定义级别的ServiceProvider来满足特定的业务需求,例如,将多个ServiceProvider组合起来以提供更高级别的服务解析和管理功能。此时,我们可以通过实现IServiceProviderFactory接口和IServiceProviderBuilder接口来创建和配置自定义级别的ServiceProvider,从而实现更灵活、可扩展的依赖注入框架。
重要对象
-
IServiceCollection: 用于注册应用程序所需的服务实例,并将其添加到依赖注入容器中。
-
IServiceScopeFactory: 用于创建依赖注入作用域(IServiceScope)的工厂类。每个IServiceScope都可以独立地管理Scoped和Transient类型的服务实例,并在作用域结束时释放所有资源。IServiceScope通过ServiceProvider属性来访问该作用域内的服务实例
-
ServiceProvider: 可以看作是一个服务容器,它可以方便地注册、提供和管理应用程序需要的各种服务。还支持创建依赖注入作用域(IServiceScope),可以更好地管理和控制服务实例的生命周期和依赖关系
-
IServiceProviderFactory: 创建最终的依赖注入容器(IServiceProvider),提供默认的DefaultServiceProviderFactory(也就是官方自带的IOC),也支持自定义的,比如autofac的AutofacServiceProviderFactory工厂。
-
ServiceProviderEngineScope: 实现了IServiceProvider和IDisposable接口,用于创建和管理依赖注入作用域(Scope)。通过使用ServiceProviderEngineScope,我们可以访问依赖注入作用域中的服务实例,并实现Scoped和Transient类型的服务实例的生命周期管理。作用域机制可以帮助我们更好地管理和控制应用程序的各个组件之间的依赖关系
-
CallSiteFactory: 通常由依赖注入容器(如ServiceProvider)在服务解析过程中使用。当容器需要解析某个服务时,它会创建一个CallSiteFactory对象,并使用其中的静态方法来创建对应的ServiceCallSite对象。然后,容器会将这些ServiceCallSite对象组合成一个树形结构,最终构建出整个服务实例的解析树。
-
ServiceCallSite: 表示服务的解析过程。它包含了服务类型、服务的生命周期、以及从容器中获取服务实例的方法等信息
-
CallSiteVisitor: 通常由依赖注入容器(如ServiceProvider)在服务解析过程中使用。当容器需要解析某个服务时,它会创建一个ServiceCallSite的对象图,并将其传递给CallSiteVisitor进行遍历和访问。CallSiteVisitor通过调用不同节点的虚拟方法,将每个节点的信息收集起来,并最终构建出服务实例的解析树。
-
CallSiteValidator 通常由依赖注入容器(如ServiceProvider)在服务解析过程中使用,用于验证ServiceCallSite对象图的正确性。它提供了一组检查方法,可以检测ServiceCallSite对象图中可能存在的循环依赖、未注册的服务类型和生命周期问题等。
二、依赖注入三个生命周期:
我们可以将依赖注入容器看作一个树形结构,其中root节点的子节点是Scoped节点,每个Scoped节点的子节点是Transient节点(如果存在)。在容器初始化时,会在root节点下创建和缓存所有单例服务的实例,以及创建第一个Scoped节点。
每个Scoped节点下都有一个独立的作用域,用于管理Scoped服务的生命周期和依赖关系,同时还继承了父级节点(即root或其他Scoped节点)的所有单例服务的实例。 在处理每个新的请求时,依赖注入容器会创建一个新的Scoped节点,
并在该节点下创建和缓存该请求所需的所有Scoped服务的实例。在完成请求处理后,该Scoped节点及其下属的服务实例也将被销毁,从而确保Scoped服务实例的生命周期与请求的作用域相对应。
1)暂时(Transient)
暂时生存期服务是每次从服务容器进行请求时创建的。 这种生存期适合轻量级、 无状态的服务。
2)作用域(Scoped)
对于 Web 应用,指定了作用域的生存期指明了每个客户端请求(连接)创建一次服务。在处理请求的应用中,在请求结束时会释放有作用域的服务。
使用 Entity Framework Core 时,默认情况下使用范围内生存期来注册 DbContext 类型。
3)单例(Singleton)
来自依赖关系注入容器的服务实现的每一个后续请求都使用同一个实例。 如果应用需要单一实例行为,则允许服务容器管理服务的生存期。
单一实例服务必须是线程安全的,并且通常在无状态服务中使用。如处理文件时候应用单例注册。
注意:不要从单一实例解析限定范围的服务,并小心不要间接地这样做,例如通过暂时性服务。 当处理后续请求时,它可能会导致服务处于不正确的状态。最直接的影响是限定范围的服务无法释放,间接成了单例模式。
一定要使用,就自己创建,并且显式管理它的生命周期。
三、依赖注入要掌握的知识点(老张的哲学)
参考来源:https://www.cnblogs.com/ysmc/p/16012269.html
https://www.cnblogs.com/xiaolipro/p/17873575.html
https://www.cnblogs.com/Z7TS/p/17402544.html
标签:Core,依赖,服务,DI,作用域,ServiceProvider,实例,Scoped,Net From: https://www.cnblogs.com/fyshao/p/18070220