先总结一下上节 依赖注入
IOC容器是控制反转 目的是 由 主动 --被动 也就是被动的让框架去实例化创建对象和销毁对象 帮助处理依赖关系 而达到这个目的 的实现手段就是DI依赖注入
小结:依赖于抽象 以及 IOC容器 服务注册得说明 来 注入 实例化对象 从而 解耦/屏蔽细节 从而在架构上让项目得重用性更高 比如大多数功能都相同 只有个别定制的内容 切换服务注册即可
知识点 概念: 1 工厂模式 2反射 (找需要注册类) 3 递归 (A-B-C引用多层就递归找,代码维护) 4 特性 (过滤 注册的内容) 5 动态代理
扩展: 内置的Ioc 只能 构造函数注入 可以使用第三方去 实现更多的 注入方式
算法 :空间换时间 太多对象类型 for循环的次数 递归找的时候引用多次 时间太长 可能造成的内存问题 先把反射找的所有类型添加到字典中 从内存拿就1对1 不用每次在循环中去找 特性过滤也是减少时间
时间换空间 太多对象 去创建的时候 空间太大 多个线程 也会内存溢出 用到对象时再去创建
接下来先了解 生命周期 以及 根容器/子容器 (容器 也可理解为 服务提供对象servicesprovider )
生命周期3种: 瞬时 单列 作用域单列 (容器单列 -- 当前容器单列)
根容器:单例 Core里面内置的 根服务容器 就是 startup里面的 IServiceCollection services 服务集合调用buildservicesprovider方法 创建的服务提供对象
子容器:瞬时和作用域单列 需要root根容器使用createscope 创建出来一个子容器范围 然后 servicesprovider属性 才是子容器 服务提供对象
每一个子容器都是平级的 子容器的子容器也就是 子容器在去createscope在创建范围在servicesprovider服务提供对象 并不是孙子容器 他们都只关注根容器
释放回收
一个应用程序 对应 一个根容器 单列 随根容器销毁 才释放 即使子容器 创建的单列 也随根容器 释放
一个 http请求过来 对应是一个 作用域单列当前子容器
请求结束 如果继承Idisposable 会随容器using使用 没有继承Idisposable的话 瞬时/作用域单列就随GC回收 啥时候用完啥时候释放 跟容器就无关了
图例 可以看到根容器 与 子容器 分别对应 应用程序 以及http请求
怎么实列化对象的?
服务集合 IServiceCollection 其实继承了 一个叫servicedescriptor 也就是 服务描述对象
服务提供对象 框架中调用 Getservice方法 的时候 根据这些服务描述 来通过构造函数 去构造 这个Getservice方法 是框架被动用的 开发中不需要去使用这个方法主动去获取的
那么既然Core内置的IOC容器最终是根据构造函数去实例化的
那里面有几点误区要注意
1:一个服务抽象 对应 多个 实现 虽然可以这么写,但是没意义 还是需要去配置服务 告诉一下
既然想让框架帮忙注入 多个实现 那注入哪个呢 就好像让别人帮忙又不说帮什么忙 所以一定要避免这种思想 确保一个服务对应一个实现
即便是封装了服务传参数去指定封装中的其中一个服务那也是选了一个罢了,归根结底还是一个
一个服务对应一个实现注册之后,当实际场景框架去实现构造函数的时候 比如控制器对象去实例化 可能多个构造函数引用了多个服务怎么办?找那个?
1 构造函数 实列化 有多个构造函数 都有参数
比如 class M(a) class M(a,b)
这样构造得时候 选哪个呢 ?
规则: 服务对象会找超集的 也就是 注册服务如果只有 a 那就是class M(a) 注册服务有 a,b 那么就是class M(a,b)
2.构造函数 实列化 有多个构造函数 都有参数
比如 class M(a,c) class M(a,b)
服务注册了 a,b,c 那么采用哪个? 这样会报错,也就是说这种 构造函数不能这样写,没有超集 谁也不服谁 那就没办法了
确保框架实例化对象时,这个对象的构造函数 满足注册的这些服务具有超集的能力去构造 当然正常情况都是一个构造函数