Surging 个人理解2
直接看添加核心服务之后的操作,本内容为个人理解
对以上11点分析如下:
1.
在addclient扩展方法中 分别注入了以上服务
1.1 注入业务模块
全局查看 继承 IServiceBehavior 接口的对象:
看一下类传递关系如下:
1.
.
2.
3.
如上为接口的定义,作者在对具有ModuleName自定义属性的接口和类分别作了注入操作。
所以:如果要新增功能,需要分别继承 IServiceKey 与 Servicebase 类 参照IUserService即可。
1.2 仓储模块的集成
由上可知,在添加仓储模块时需要继承 BaseRepository 类
1.3 RegisterServiceBus
IIntegrationEventHandler 集成事件接口如下:
此范型使用了 in参数 在进行实例化时 需要传入子类或同类 可参考 https://www.cnblogs.com/xianyudotnet/archive/2016/07/26/5706991.html 对范型中 in out 的理解
实现类:
具体 此方法是在执行哪个步骤时调用的呢? 通过这里作者示例 可以明白 RegisterServiceBus 应该是一种事件总线机制
通过 QueueConsumerAttribute 自定义属性查找这种 事件的调用机制
结果为 EventBusRabbitMQ 组件中的 事件订阅机制 这个组件放后面讲
1.4 注入模块
添加模块共分为3部分 首先第一部 如何找到 packages
第一步的 package是空的 ,其实并未读配置 - ——-
第二步 看一下GetAbstractModules方法
从整个应用程序集下查找继承 过 AbstractModule 类的对象 并创建实例:
看一下 所有继承 AbstractModule的对象
首先
继承自 autofac的 模块 ,产生了模块化注入的方式
所有继承抽像类的类
分别为 BusinessModule 、EnginePartModule 、 SystemModule 模块3种模块基类菜用了相同的初始化与注册组件的方法
这些没什么可看的,可能作者也是方便大家自己扩展。
看一下AbstractModule 中的初始化与注册组件做了哪些工作
抽像基类中的初始化方法并未做任何操作
load 方法 分判断组件是否可用,并注册模块组件
组件的创建会根据组件定义的生命周期进行分别注入,如依赖创建与单例模式,默认会采用依赖创建方式。
顺便说一下验证模块的方法:
只须保证模块相关信息填写符合要求即可。
第三步:ModuleProvider
同样 在这个类中的初始化方法中会判断是否可用并开始调用各个模块的初始化方法,
但是模块的初始化方法并未有内容,所以在该步中并未初始化模块,只是构造了一个模块提供器
这时候 模块功能好像并未加载
1.5 调过这个功能 看下个方法 客户端运行时服务
运行时服务首先会添加 默认的健康检查服务、默认的地址解析服务、远程调用服务
服务可用性检查服务DefaultHealthCheckService
在构选函数中
每10秒会检查一次服务状态,在构造函数中添加服务路由管理事件。
IServiceRouteManager
重点看一下 获取 设置 移除 清空
可以找到 类 ServiceRouteManagerBase 在此类中只有对设置 做了虚方法实现
其它方法做为抽像类实现了接口
看一下 设置
这里需要一个ServiceRouteDescriptor 服务路由描述符 其实只有一个地址模型 AddressModel
同样 设置方法也是 再次调用了一个抽像方法。
那这些实现方法在哪呢?
全局搜一下
首先 CPlatform中的重写
SharedFileServiceRouteManager 共享文件服务路由管理 基于文件的服务路由操作 此处的扩展有可能是当不使用consul和zookeeper时使用文件管理服务路由
了解一下 FileSystemWatcher
https://www.cnblogs.com/zxbzl/p/5863999.html
SharedFileServiceRouteManager 类并无特点要说明的,只有一个方法可以了解一下
我们找一下 这个OnCreated事件是如何邦定方法的
此事件 定位在 IServiceRouteManager 中 ,我们找到 IServiceRouteManager 接口
并未有邦定事件的方法的代码,继续查找
在添加核心服务时会添加一个默认的服务路由提供者 DefaultServiceRouteProvider 如下为构造方法
从这里可以看到 在将这个类进行构造时就已经邦定好事件了,666 找了好久...
其它的 文件共享代码并无难点 ,基于文件存储方式保存路由信息
说一说 consul 中的 方法重写
consul 与 zookeeper 均为服务发现服务注册组件
看一下他们的对比
https://blog.csdn.net/iie_libi/article/details/78755195
框架中内置了consul 与 zookeeper 并最终选择了consul 作为服务发现、服务注册组件,
看一下对服务路由的管理
这里采用了异步删除服务路由的操作,具体我们看一下 _configInfo.RoutePath 这个参数是如何得到值的
在 ConsulServiceRouteManager 服务路由管理 构造方法中 首先创建了一个 consulclient 对象,
consulclient 相对于其它服务发现来说,仅需要一个配置地址即可
我们看一下 EnterRouters()方法 wait() 表示需要等待这个方法执行完,才会构造完这个类
以上是 子节点变更事件,同样 我们找一下 OnRemoved OnCreated 事件邦定的方法
同样 在 核心服务中 的默认服务路由提供者中可以找到对事件的邦定
具体 我们来看看 事件做了哪些事
删除与新增均是对
当前线程集合中的服务路由进行操作。
--------------------------------------------------------------------------------------------------
同样在服务地址解析中 看一下对于服务路由管理的事件操作
全部是在线程字典中进行 删除与修改
ConcurrentDictionary 是一种线程安全的字典集合 类似与 dictionary
--------------------------------------------------------------
RemoteInvokeService 类作用如下:
远程对象调用服务
分别对 各接口实现分析如下:
1.Task<RemoteInvokeResultMessage> InvokeAsync(RemoteInvokeContext context);
2个问题 a. Task.Factory.CancellationToken 方法的作用 MSDN 讲这是一个作务取消的标记,具体看看在方法中的作用
第一步:
首选 看一下 对 RemoteInvokeContext 类的构建
重点关注一下 Item 值 是什么意思 通过
此方法为构建item的方法体,在只有负载为hash一致性时才会使用传入的第一个参数,如果为别的类型 item为空
第一步中解析地址方法如下
重点关注上图方法红框
首先 关注一下 ValueTask 与 Task的区别
https://blog.scooletz.com/2018/05/14/task-async-await-valuetask-ivaluetasksource-and-how-to-keep-your-sanity-in-modern-net-world/
其实按个人理解为 如果只是想获取一个值 但是方法体是异步的时候 使用 ValueTask
-------------------------------------------------
1.从字典中拿到serviceroute对象
2.从字典中拿到服务描述符集合
3.获取或添加serviceroute
4.添加服务id到白名单
5.根据服务描述符得到地址并判断地址是否是可用的(地址应该是多个)
6.添加到集合中
7.拿到服务命今
8.根据负载分流策略拿到一个选择器
9.返回addressmodel
------------------------------------------------------------------------
地址创建完了,看一下基于DotNetty的传输客户端工厂,具体可了解知识点 DotNetty 一种更高效的网络传输框架。
https://www.cnblogs.com/xuanye/p/dotnetty-quickstart.html
如上为根据终端创建一客户端,具体讲到组件时再分析这个类 现在只须了解作者在的思路即可
由上可知:在创建失败时会标记这个地址是无效的并抛掉异常。
紧接着 创建完之后 发送了调用信息
如上,调用发送并添加了回调方法 个人理解 发送成功之后会立即进入回调方法
看一下回调
首先了解一下 ManualResetValueTaskSource 类
初始化对象方便调用 现在看来取消任务标记并未起到作用,根据对 manual理解 为手动重置、以及类中version的定义
同时在 finally中 作者 调用了取消任务,表明在任务调用一次返回值之后取消掉了这个任务,交由GC回收。
-------------------------------------------------------------------
RandomAddressSelector 原则
随机取下标值进行地址调用
轮询的地址选择器 PollingAddressSelector
了解一下 GetAddress()
其实原理相对不难,找到一个没有使用的地址即可。(index会重置为0 这样就是一无限循环地址,直到找到一个合适的地址)
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.interlocked.exchange?redirectedfrom=MSDN&view=netframework-4.7.2#System_Threading_Interlocked_Exchange_System_Int32__System_Int32_
-----------------------------------------------------------------------
FairPollingAdrSelector
同样
使用了相同的方法
重点在 do while 方法不同 当地址为 不可用时会跳出 或者达到最后一个 这一点暂未明白逻辑 和轮询差不多。
------------------------------------------------
关注一下 ConsistentHash 类
同上红框 分在字典中建立 大于等于10 个hash节点对像,通过do while 调用 getItemNode传入当前 AddressSelectContext中的一个节点item
得到一个 有效的hash节点 ,得出之后移除不能用的节点
do while 操作添加事件 不明觉厉
-------------------------------------------------------------
---------------------------------------------------------------------------------------------------
这个方法 注入了3个接口 IClrServiceEntryFactory 、IServiceEntryProvider、IServiceEntryManager
分别看一看 这三种接口的实现
IClrServiceEntryFactory
CreateServiceEntry 在所有标记过 ServiceBundle的类上会找到相关的方法进行创建
看一下Create的具体实现
重点一 可以在方法上加入授权 添加 AuthorizationFilterAttribute 代码控制 授权 日志 操作
重点二 在容器中获取委托并被调用。
-----------------------------------------------------------------------------------------------------------------
IServiceEntryProvider 创建器
---------------------------------------------------------------------------------------------------------------------
IServiceEntryManager
在进行构造时就调用了赋值操作
-------------------------------------------------------------------------------
分别了解一下如下类型 ServiceCommandProvider、BreakeRemoteInvokeService、FailoverInjectionInvoker
ServiceCommandProvider 类 主要是对服务命令进行维护管理 再次了解一下 ConcurrentDictionary <T,T> 这种 类型 是一种线程安全的字典集合,
所以数据都会在保存单一线程内部,使用时从此线程内部拿到。