依赖注入在 dotnet core 中实现与使用:1 基本概念
关于 Microsoft Extension: DependencyInjection 的介绍已经很多,但是多数偏重于实现原理和一些特定的实现场景。作为 dotnet core 的核心基石,这里准备全面介绍它的概念、原理和使用。 这里首先介绍概念部分。 1. 概念该项目在 GitHub 的地址:https://github.com/aspnet/Extensions/tree/master/src/DependencyInjection
1.1 问题的场景在软件开发中,项目通常有多个不同的模块组成,模块之间存在依赖关系。例如,我们考虑一个简化的场景,我们有 3 个关于用户的类:
1.2 依赖倒置原则 DIP依赖倒置原则是广为人知的设计原则之一,该原则是实现软件项目中模块的解耦的理论基石。 原则的定义如下:
翻译过来为:
在没有实现依赖倒置原则的时候,我们通过在 public class AccountController { ? private readonly UserService _userService; public AccountController() { this._userService = new UserService(); } } ? 这导致了两个类之间的紧耦合, 基于依赖倒置的原则,通常会考虑通过接口进行隔离。例如,我们可能会定义一个用户服务的接口: public interface IUserService { } ? 而用户服务则会实现该接口 public class UserService : IUserService { } ? 在 public class AccountController { ? private readonly IUserService _userService; public AccountController() { this._userService = new UserService(); } } ? 虽然在 1.3 控制反转 IoC
它的核心思想是:在需要对象实例的时候,不要总考虑自己通过 在需要对象实例的时候,从这个 下面是一个广泛使用的示意图。拿总是要拿的,但是从 自己穿上 变成了 给你穿上 在控制反转中,引入了一个?ServiceProvider 来帮助我们获得对象实例。 ? 1.4 依赖注入 DI (DependencyInjection)DI 是 IoC 模式的一种实现。 《Expert one on one J2EE Development without EJB》第 6 章
Martin Fowler 的原文:
大意是:
DI 的实现有多种,我们这里介绍的是微软官方在 Microsoft Extension 中内置提供的 DependencyInjection。它是 IoC 中一种实现,ASP.NET Core 的整个核心基于它来实现。同时,我们也可以在其它项目中使用,以实现对依赖倒置原则的支持。 2. DependencyInjection 中的基本概念2.1 服务描述集合 ServiceCollection在微软的 DI 实现中,所有的服务需要首先注册到一个公共的服务描述集合中,该集合对于整个 DI 来说,只需要一个,服务只需要在此集合中注册一次,即可在以后通过 DI 提供给使用者。 该集合的接口定义为 public interface IServiceCollection : IList<ServiceDescriptor>,ICollection<ServiceDescriptor>,IEnumerable<ServiceDescriptor>,IEnumerable { } ? 系统默认已经实现了一个对 IServiceCollection services = new ServiceCollection ();
? 2.2 服务 Service在 DI 语境中,服务特指通过 DI 容器管理的对象实例。这个服务并不一定被称为 **Service,而是可以是任何由 DI 所管理的对象,只是在 DI 这个语境下,我们将其统称为服务。 服务是我们自己定义的,例如前面提到的 我们通过 DI 来获得服务对象实例,管理服务对象的生命周期,对于存在复杂依赖关系的对象, DI 还负责管理这些实例之间的依赖关系。 服务必须首先注册在 DI 中才能使用,但是,注册前需要首先考虑和决定服务的生命周期。 2.3 服务的生命周期服务对象实例有着不同类型的生命周期。有些对象的生命周期与应用程序相同,在应用程序启动时创建,在应用程序退出时才需要释放。例如我们的数据访问对象实例。有些对象仅仅在当前方法中使用,在方法调用结束之后就应该销毁。服务的生命周期管理用来管理这些需求。 DI 支持三种类型的生命周期:
Microsoft.Extensions.DependencyInjection.ServiceLifetime public enum ServiceLifetime { Singleton,Scoped,Transient } ? 服务的生命周期在注册服务的时候确定。在使用的时候,直接获取实例,不再指定服务的生命周期。微软提供了多种扩展方法来便于在注册服务时指定服务的生命周期。例如下面是通过泛型方式来指定单例模式的生命周期。 // 基于接口的注册 services.AddSingleton<IUserService,UserService>(); ? 2.4 服务提供者 ServiceProvider在需要使用服务对象实例的时候,不是从注册服务的集合中获取,而是需要通过服务提供者来获取,这个服务提供者显然需要来自注册服务的集合。服务提供者的接口定义为 public interface IServiceProvider { object GetService(Type serviceType); } ? DI 中的 public static ServiceProvider BuildServiceProvider(this IServiceCollection services) { return BuildServiceProvider(services,ServiceProviderOptions.Default); } ? 所以,我们通常使用该方法来获取并使用它。 // 创建注册服务的容器 IServiceCollection services = new ServiceCollection (); // 注册服务,这里指定了单例 services.AddSingleton<IUserService,UserService>(); // 通过容器获得服务提供者 IServiceProvider provider = services.BuildServiceProvider (); ? 2.5 获取服务对象实例通过服务提供者来手动获取服务对象实例。通过注册的服务类型,直接调用 例如,前面我们注册了服务类型 // 创建注册服务的容器 IServiceCollection services = new ServiceCollection (); // 注册服务,这里指定了单例 services.AddSingleton<IUserService,UserService>(); // 通过容器获得服务提供者 IServiceProvider provider = services.BuildServiceProvider (); // 通过接口获取服务对象实例 IUserService instance = provider.GetService<IUserService> (); ? 看起来,更加复杂了。在实际使用中,我们很少使用这样的方式来使用 DI,后面我们再深入讨论具体的使用过程。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |