,并且将模块加载器对象作为服务引擎的LoadModules()
方法参数:
public static IEngine AddSilkyServices<T>(this IServiceCollection services, IConfiguration configuration,IHostEnvironment hostEnvironment) where T : StartUpModule{var moduleLoader = new ModuleLoader();engine.LoadModules<T>(services, moduleLoader);}
在服务引擎SilkyEngine
实现类中,除了实现IEngine
接口之外,还需要实现了IModuleContainer
接口,IModuleContainer
只定义了一个只读属性Modules
,要求通过该属性获取所有的模块;在服务引擎中,我们通过模块加载器对象moduleLoader.LoadModules()
方法实现对模块的加载与解析,并对属性Modules
进行赋值;
internal sealed class SilkyEngine : IEngine, IModuleContainer{// 其他代码略...public void LoadModules<T>(IServiceCollection services, IModuleLoader moduleLoader)where T : StartUpModule{Modules = moduleLoader.LoadModules(services, typeof(T));}// 实现IModuleContainer定义的属性public IReadOnlyList<ISilkyModuleDescriptor> Modules { get; private set; }}
模块加载器ModuleLoader要求传递两个参数,一个是IServiceCollection
的对象services
,一个是启动模块StartupModule
的的类型typeof(T)
;下面我们来描述模块加载的过程:
- 通过
SilkyModuleHelper.FindAllModuleTypes(startupModuleType)
查找到启动模块StartupModule
类型依赖的所有模块类型;
- 通过反射创建模块的实例,并通过
IServiceCollection
注册单例的模块实例,并创建模块描述符SilkyModuleDescriptor
;
- 根据模块的依赖关系对模块进行排序;
DependsOnAttribute
指定的,通过DependsOnAttribute在对模块的类进行标注,就可以解析到各个模块的依赖关系,从而实现通过模块的依赖关系进行排序;提示熟悉APB框架的小伙伴应该可以看出来,Silky模块的设计主要是借鉴了APB框架的模块设计,在一些细节方面做了调整 。Silky的核心模块通过上面的介绍, 我们知道一个模块类的最重要的工作主要由两点: 1. 实现服务的注册; 2. 在应用启动时或是停止时执行指定的方法完成初始化任务或是释放资源的任务;
如何判断是否是silky的核心模块呢? 核心模块最重要的一个作用就是在应用启动时,通过
Initialize()
方法执行该模块的初始化资源的任务;通过查看源码,我们发现大部分silky模块在应用启动时并没有重写
Initialize()
方法,也就是说,大部分silky模块在应用启动过程时主要是完成各个模块的服务类的注册并不需要做什么工作 。
文章插图
如上图所示,我们看到silky框架定义的模块,由如上几个模块是在应用启动是完成了主机启动时的关键性作业;
我们再根据模块的依赖关系,可以看到主机在应用启动时,通过模块初始化任务的一个执行顺序如下所示:
RpcModule --> DotNettyTcpModule | TransactionModule | WebSocketModule | [RpcMonitorModule] --> GeneralHostModule(启动模块[StartUpModule])[DefaultGeneralHostModule|WebSocketHostModule|DefaultWebSocketHostModule]
通过上述的依赖关系,我们可以知道:- Rpc模块在应用启动时是最早被执行;
- 然后依次执行: DotNettyTcpModule | TransactionModule | WebSocketModule | [RpcMonitorModule] 等模块;
- 最后执行应用启动模块指定的初始化方法;