Silky微服务框架在线文档Silky微服务框架在线文档
首页
文档
配置
源码解析
博文
github
gitee
  • 简体中文
  • English
首页
文档
配置
源码解析
博文
github
gitee
  • 简体中文
  • English
  • 简介

    • silky 框架介绍
  • 入门

    • 名词解释
    • 快速开始
    • 脚手架
    • 微服务模块化架构的最佳实践 & 约定
    • 示例
  • 主机与模块

    • 主机
    • 网关
    • 模块
    • 插件
  • 网关与 HTTP

    • Swagger 文档
    • 性能分析(MiniProfiler)
    • 跨域(CORS)
    • 审计日志
  • 服务与 RPC

    • 应用服务和服务条目
    • rpc通信
    • websocket通信
    •  服务注册中心
    • 服务治理
  • 数据与缓存

    • EFCore 数据访问
    • 缓存
    • 分布式锁
  • 安全与认证

    • 身份认证与授权
    • 分布式事务
  • 基础设施

    • 依赖注入
    • 对象到对象的映射
    • 参数验证
    • 链路跟踪
    • 日志(Serilog)
    • 健康检查
    • 消息总线(MassTransit)
    • 单元测试与集成测试

模块的定义和类型

在silky框架,模块是应用程序用于服务注册、初始化任务、释放资源的单位,被定义为一个程序集。模块具有依赖关系,通过DependsOn特性来确定模块之间的依赖关系。

silky框架存在两种类型的模块:

  1. 开发者通过继承SilkyModule就可以定义一个普通模块类;
  2. 如果需要自定义启动模块,可以继承框架提供的主机模块基类(如 GeneralHostModule、WebHostModule、GatewayHostModule),这些基类本身也继承自 SilkyModule,并已声明了对应主机类型所需的模块依赖。

例如:

普通模块类

// 普通模块类,启动模块类必须要直接或间接的依赖该模块
[DependsOn(typeof(RpcModule))]
public class CustomModule : SilkyModule
{
}

自定义启动模块类(以普通业务主机为例)

// 继承 GeneralHostModule 可自动获得 DotNetty、RPC、TCC 等通用依赖
// 只需额外声明本项目所需的依赖模块即可
[DependsOn(
    typeof(ZookeeperModule),    // 注册中心
    typeof(AutoMapperModule)    // 对象映射
)]
public class NormHostModule : GeneralHostModule
{
}

提示

  1. 开发者想要加载某个模块,需要在注册微服务时将其指定为启动模块,或通过 DependsOn 特性直接或间接依赖该模块。

  2. 在调用 RegisterSilkyServices<T>() 时,泛型参数 T 指定的模块即为启动模块。框架要求 T 必须是 SilkyModule 的子类,普通模块和主机模块均可作为启动模块。

在模块中注册服务

模块提供了两个服务注册的API,一是通过ServiceCollection实现服务注册,二是通过ContainerBuilder实现服务注册。

通过ServiceCollection实现服务注册

开发者通过重写ConfigureServices方法,可以通过IServiceCollection实现服务注册,例如:

public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
    services.AddOptions<RpcOptions>()
        .Bind(configuration.GetSection(RpcOptions.Rpc));
    services.AddOptions<GovernanceOptions>()
        .Bind(configuration.GetSection(GovernanceOptions.Governance));
    services.AddOptions<WebSocketOptions>()
        .Bind(configuration.GetSection(WebSocketOptions.WebSocket));
    services.AddDefaultMessageCodec();
    services.AddDefaultServiceGovernancePolicy();
}

通过ContainerBuilder实现服务注册

ContainerBuilder 是 Autofac 提供服务注册的类,开发者可以通过重写RegisterServices方法使用ContainerBuilder提供的API实现服务注册。使用ContainerBuilder注册服务的一个优势是可以注册命名的服务。

protected override void RegisterServices(ContainerBuilder builder)
{
    builder.RegisterType<DefaultExecutor>()
        .As<IExecutor>()
        .InstancePerLifetimeScope()
        .AddInterceptors(
            typeof(CachingInterceptor)
        )
        ;
}

模块的初始化方法

在应用程序启动过程中,开发者可以重写PreInitialize、Initialize、PostInitialize方法来实现模块的初始化任务之前、初始化任务、初始化任务之后的方法。

开发者可以通过applicationContext.ServiceProvider属性来解析注册的服务。


public virtual Task PreInitialize(ApplicationInitializationContext context)
{
    return Task.CompletedTask;
}

public override async Task Initialize(ApplicationInitializationContext context)
{
    var serverRouteRegister =
        context.ServiceProvider.GetRequiredService<IServerRegister>();
    await serverRouteRegister.RegisterServer();
}

public virtual Task PostInitialize(ApplicationInitializationContext context)
{
    return Task.CompletedTask;
}

使用模块释放资源

在应用程序正常停止时,通过重写Shutdown方法来实现模块停止时需要执行的方法,例如:释放资源等。

public override async Task Shutdown(ApplicationShutdownContext context)
{
    var serverRegister =
        context.ServiceProvider.GetRequiredService<IServerRegister>();
    await serverRegister.RemoveSelf();
}

模块的依赖关系

silky框架的模块通过DependsOn特性指定模块的依赖关系,silky框架支持通过直接或是间接的依赖模块。例如: NormHostModule模块依赖了DotNettyTcpModule模块,DotNettyTcpModule模块依赖了RpcModule模块,微服务注册时指定NormHostModule为启动模块。那么根据模块依赖关系,RpcModule模块会被应用加载,并先于DotNettyTcpModule和NormHostModule执行服务注册方法和初始化方法。

开发者只需要通过DependsOn特性在类直接就可以指定该模块依赖的模块,在应用启动过程中,会根据模块的依赖关系进行排序。并完成服务注册方法和指定的初始化方法。

例如,NormHostModule的模块依赖关系如下所示:

// 继承 GeneralHostModule 已隐含对 DotNettyTcpModule、RpcProxyModule、TransactionTccModule 等的依赖
[DependsOn(
    typeof(ZookeeperModule),    // 注册中心
    typeof(AutoMapperModule)    // 对象映射
)]
public class NormHostModule : GeneralHostModule
{
}

构建主机时指定启动模块

开发者如果自定义了模块,那么,需要在构建微服务主机时,指定启动模块。

例如:


private static IHostBuilder CreateHostBuilder(string[] args)
{
    return Host.CreateDefaultBuilder(args)
            .RegisterSilkyServices<NormHostModule>() // 指定启动模块,框架约束 T 必须是 SilkyModule 的子类
        ;
}

一般地,开发者在构建默认主机时,并不需要指定启动模块。构建的默认主机,已经根据构建的主机类型,指定了默认的启动模块。例如,使用ConfigureSilkyWebHostDefaults构建silky主机时,已经指定了DefaultWebHostModule作为其中模块。

如果开发者有自定义模块时,同时也需要自定义一个启动模块,通过该启动模块依赖开发者自定义的模块和 silky 框架定义的模块,达到服务注册和初始化任务的目的。

例如:

// 继承 GeneralHostModule,在其基础上追加项目自定义模块
[DependsOn(
    typeof(ZookeeperModule),   // 注册中心
    typeof(AutoMapperModule),  // 对象映射
    typeof(CustomModule),      // 自定义业务模块
)]
public class CustomStartHostModule : GeneralHostModule
{
}

为了方便开发者,silky框架根据构建主机的类型,已经创建了多种启动模块,该类型的启动模块已经定义好了该模块必须的依赖的模块:

  1. 通过web主机构建微服务应用的WebHostModule模块
  2. 通过通用主机构建微服务应用的GeneralHostModule模块
  3. 构建websocket服务主机的应用的WebSocketHostModule模块
  4. 构建只能作为服务消费者网关应用的GatewayHostModule模块

开发者可以选择继承如上的启动模块,并且配置Host主机提供API就可以构建相应的主机。

以插件的方式注册模块

在模块的依赖关系设置中,我们知道开发者除非改写启动模块,不然无法将用户扩展的模块添加到应用服务的依赖中;但是,改写启动模块时一件麻烦的工作,我们在开发中可以尽量避免启动模块的修改;

Silky提供给开发者可以通过模块插件的方式将模块添加到应用模块中,这样模块在应用启动时也将会被执行。

例如:用户自定义了一个模块TestModule,用于在应用启动时,通过该执行数据库迁移:

public class TestModule : SilkyModule
{
    public override Task Initialize(ApplicationInitializationContext context)
    {
        if (context.HostEnvironment.IsDevelopment())
        {
            // using var scope = context.ServiceProvider.CreateScope();
            var demoDbContext = context.ServiceProvider.GetRequiredService<DemoDbContext>();
            return demoDbContext.Database.MigrateAsync();
        }
        return Task.CompletedTask;
    }
}

我们知道如果我们没有指定在启动模块中依赖该模块的话,该模块在应用启动时是得不到执行的,但是修改启动模块是一件比较麻烦的事; 我们可以通过配置的方式,指定改模块为插件模块,这样就可以通过配置的方式将模块加入到应用启动时.

在appsettings.yaml配置文件下增加如下配置:

plugInSource:
  modulePlugIn:
    types:
    - TestApplication.TestModule,TestApplication # 模块所在类的完全限定名,应用程序集
编辑当前页
Prev
网关
Next
插件