3.1依赖注入

简介: 传统开发中,对象都是开发者创建组装,开发者必须了解各类的使用方法且某些类的耦合度较高,例如想把sql serve数据库改为MySql数据库则需要更改某些代码。控制反转的目的是让框架完成对象的创建和组装。从“我创建对象”编程“我要对象”

3.1依赖注入

控制反转

传统开发中,对象都是开发者创建组装,开发者必须了解各类的使用方法且某些类的耦合度较高,例如想把sql serve数据库改为MySql数据库则需要更改某些代码。

控制反转的目的是让框架完成对象的创建和组装。从“我创建对象”编程“我要对象”,实现控制反转主要有两种方式:

服务定位器

假设框架中有个ServiceLocator类,可以直接调用GetService方法便可以获得想要的对象。

IDbConnection con = ServiceLocator.GetService<IDbConnection>();

依赖注入

一个对象中需要包含其他类型的对象,则在创建该对象的时候,框架会自动创建所需类型的对象。

容器:负责提供对象的注册和获取功能的框架

服务:注册到容器中的对象

依赖注入的基本使用

声明周期:获取服务的时候是创建一个新对象还是用之前对象

  1. 瞬态(transient):每次请求都创建一个新对象。
  2. 范围(scoped):在给定范围内,多次请求共享一个对象;在不同范围内,服务每次被请求的时候返回不同对象。ASP.NET Core中,同一次http请求,不同的注入会获得同一对象。
  3. 单例(singleton):全局共享一个服务对象。

使用建议:

如果一个类无状态,建议设置为单例;否则,框架环境有范围控制,则周期设置为范围;使用瞬态周期时要尽可能在自范围中使用,否则容易造成内存泄漏。

不同服务之间具有依赖关系,A服务有一个B服务的属性,那么B的声明周期不能比A短

依赖注入框架中注册服务的时候,可以设定服务类型和实现类型,这两者可以不相同。例:

  • 服务和实现类型都是SqlConnection时,在获取SqlConnection服务时,会返回SqlConnection对象
  • 服务是IDbConnection接口类型,实现类型都是SqlConnection时,在获取IDbConnection接口服务时,会返回SqlConnection对象

服务定位器案例:

usingMicrosoft.Extensions.DependencyInjectiony;

   

 

publicinterfaceITestService

{

   publicstringName { get; set; }

   publicvoidSayHi();

}

publicclassTestServiceImpl : ITestService

{

   publicstringName { get; set; }

   publicvoidSayHi()

   {

       Console.WriteLine($"Hi, I'm {Name}");

   }

}

//获取服务之前要先注册服务

ServiceCollectionservices=newServiceCollection();//1.创建用于注册服务的容器

//AddTransient、AddScoped、和AddSingleton分别注册瞬态、范围、单例服务

services.AddTransient<TestServiceImpl>();//2.注册一个瞬时服务,注册的服务必须涵盖程序中所有的所需服务

//ServiceProvider服务定位器

using (ServiceProvidersp=services.BuildServiceProvider())//3.获取服务定位器

{

   //4.通过调用GetRequiredService方法获得对象

   TestServiceImpltestService=sp.GetRequiredService<TestServiceImpl>();

   testService.Name="tom";

   testService.SayHi();

}

依赖注入案例

接口---要注册的服务

interfaceIUserBiz{publicboolCheckLogin(stringuserName, stringpassword);}

interfaceIUserDAO{publicUser?GetByUserName(stringuserName);}

实现类

classUserBiz : IUserBiz

{

   privatereadonlyIUserDAOuserDao;//所依赖的对象

   publicUserBiz(IUserDAOuserDao) //构造函数中要求容器中必须注入IUserDAO服务

   {

       this.userDao=userDao;

   }

   publicboolCheckLogin(stringuserName, stringpassword)

   {...

   }

}

classUserDAO: IUserDAO

{

   privatereadonlyIDbConnectionconn;//所依赖的对象

   publicUserDAO(IDbConnectionconn)//构造函数中要求容器中必须注入IDbConnection服务

   {

       this.conn=conn;

   }

   publicUser?GetByUserName(stringuserName)

   {...

   }

}

组装服务

ServiceCollectionservices=newServiceCollection();//1.创建用于注册服务的容器

//2.注册的服务必须涵盖程序中所有的所需服务

//注册IDbConnection服务

services.AddScoped<IDbConnection>(sp=> {

   stringconnStr="Data Source=.;Initial Catalog=DI_DB;Integrated Security=true";

   varconn=newSqlConnection(connStr);

   conn.Open();

   returnconn;

});

services.AddScoped<IUserDAO, UserDAO>();//2.1.上面指定需要注入IUserDAO服务,但是要用UserDAO类来实现

services.AddScoped<IUserBiz, UserBiz>();

using (ServiceProvidersp=services.BuildServiceProvider())//3.获取服务定位器

{

   varuserBiz=sp.GetRequiredService<IUserBiz>();

   boolb=userBiz.CheckLogin("yzk", "123456");

   Console.WriteLine(b);

}

依赖注入的传染性:一个对象是通过依赖注入创建的,那么这个类的构造函数中所有的参数都是依赖注入赋值。但是如果一个类是手动创建,那么构造函数中所有的参数不是依赖注入。所以一旦使用依赖注入,则应避免使用new来创建。

如果一个服务有多个实现对象,可以被参数声明为IEnumerable<T>类型


相关文章
|
XML Java 数据格式
依赖注入~
依赖注入~
|
Java 测试技术 容器
Spring框架-ObjectProvider更加宽泛的依赖注入
从上面的过程中我们可以看出,但Spring中某个Bean的依赖类型为ObjectProvider时,我们不需要提供一个ObjectProvider类型的Bean到容器中,只需要提供一个T类型的Bean到容器中,容器会自动将其包装成一个ObjectProvider,然后注入到依赖中
191 0
|
2月前
|
设计模式 Java 开发者
面向切面编程和依赖注入
【9月更文挑战第6天】在软件开发中,面向切面编程(AOP)和依赖注入(DI)是提升代码可维护性、可扩展性和可测试性的关键概念。AOP 通过将横切关注点(如日志记录、事务管理)从业务逻辑中分离并模块化管理,增强了代码的清晰度和灵活性;DI 则通过外部容器管理对象间的依赖关系,降低了对象耦合度,使代码更易测试和维护。两者结合使用能显著提升软件开发效率和质量。
|
3月前
|
设计模式 测试技术 容器
依赖注入与控制反转:理解与应用
【8月更文挑战第22天】
123 0
|
6月前
|
容器
IOC 控制反转和DI依赖注入
IOC 控制反转和DI依赖注入
|
设计模式 Java Spring
依赖注入
依赖注入
|
Java Maven
SpringFrame-ioc 依赖注入
SpringFrame-ioc 依赖注入
|
程序员 容器
控制反转与依赖注入
控制反转与依赖注入
128 0
控制反转与依赖注入
|
XML 架构师 关系型数据库
|
自动驾驶 小程序 Java
什么是控制反转(IOC)?什么是依赖注入?
什么是控制反转(IOC)?什么是依赖注入?
什么是控制反转(IOC)?什么是依赖注入?