个人解读《ABP微服务解决方案示例》

参考:

ABP官网中文文档

abp官网的文档:微服务解决方案示例 (注意,要配合文档去运行项目,然后反复、认真看文档,文档中已经把项目的细节讲得足够清楚的了,包含:项目引用、依赖、远程调用过程、通信、网关等等)

有大佬为abp的微服务项目进行了讲解和扩展:[Abp vNext微服务实践] - 文章目录----一曲肝腸斷录

下载ABP全部示例代码

ABP示例github下载地址,默认是master,也可以选择最新的版本

 

ABP微服务架构简略图

 

 

问题

MongoDb

问题:BloggingService.Host(博客服务)运行失败,提示MongoDb单台服务器不支持事务,目前我下载的是abp3.2.1版本。说明文档中的MongoDB中提到新版本好像已经解决这个问题,不过微服务示例还没有升级到最新版。

虽然有个服务运行失败,而且我也没安装ElasticSearch、Kibana,但项目还是能够运行起来演示products的效果。

RabbitMQ

问题:目前使用的是3.2.1版本的,发现停止RabbitMQ服务和注释RabbitMQ代码都能正常演示

结论:这个ABP微服务示根本就没有使用RabbitMQ进行消息通信,只不过是有几个项目有引入RabbitMQ模块但是没有使用,微服务示例文档中居然说是使用RabbitMQ通信的,有点误导人。

应该是使用 动态 C# API 客户端 来通信的

项目结构

调用顺序:applications(应用层),项目引用:modules(模块层)、shared(共享层) =》gateways(网关 / 前端后端层)  =》microservices(微服务层)

applications(应用层):控制台应用程序 + UI + 身份认证

这些是具有用户界面以与用户交互并使用系统的实际应用程序.

  • AuthServer.Host  44399: 托管IdentityServer4以向其他服务和应用程序提供身份验证服务. 它是一个单点登录服务器,包含登录页面.
  • BackendAdminApp.Host  44354: 这是一个后端管理应用程序,用于托管身份和产品管理模块的UI.

  • PublicWebSite.Host  44335: 作为包含简单产品列表页面和博客模块UI的公共网站.

  • ConsoleClientDemo: 一个简单的控制台应用程序,用于演示C#应用程序中使用服务.

 

gateways(网关 / 前端后端层):控制台应用程序 + 网关 + 通信

网关用于为应用程序提供单一入口点.它还可以用于速率限制,负载平衡等. 使用Ocelot类库.

  • BackendAdminAppGateway.Host  44315: 由BackendAdminApp.Host应用程序用作后端.
  • PublicWebSiteGateway.Host  44397: 由PublicWebSite.Host应用程序用作后端.

  • InternalGateway.Host  44329: 用于服务间通信(微服务之间的通信).

 

microservices(微服务层):控制台应用程序 RabbitMQ + 身份认证 + EFCore

微服务没有UI,但暴露了一些REST API.

  • IdentityService.Host  44368: 托管用于管理用户和角色的ABP Identity模块. 它没有其他服务,仅托管Identity模块的API.
  • TenantManagementService.Host  44336: 托管用于管理角色的ABP租户管理模块. 它没有其他服务,仅托管租户管理模块的API.

  • BloggingService.Host  44357: 托管ABP博客模块,该模块用于管理博客和帖子(典型的博客应用程序). 它没有其他服务,仅托管Blogging模块的API.

  • ProductService.Host  44344: 托管用于管理产品的产品模块(位于解决方案内). 它还包含用于创建/更新产品管理数据库架构的EF Core迁移.

 

modules(模块层):类库 + DDD + DTO + 实体类 

项目名称都是带有 Management 字眼的

包含基于DDD原则分层的实际模块:

产品: 使用模块开发最佳实践开发的分层模块. 它可以嵌入到单个应用程序中,也可以通过单独部署API和UI作为微服务托管

  • ProductManagement.Domain.Shared: 包含所有层之间共享的常量和类型.
  • ProductManagement.Domain: 包含域逻辑并定义实体,域服务,域事件,业务/域异常.

  • ProductManagement.Application.Contracts: 包含应用程序服务接口和DTO.

  • ProductManagement.Application: 包含应用程序服务的实现.

  • ProductManagement.EntityFrameworkCore: 包含DbContext和其他与EF Core相关的类和配置.

  • ProductManagement.HttpApi: 包含API控制器.

  • ProductManagement.HttpApi.Client: 包含C#代理以远程直接使用HTTP API. 使用ABP的Dynamic C#API客户端功能.

  • ProductManagement.Web: 包含UI元素(页面,脚本,样式..等).

 

shared(共享层):类库

  • MsDemo.Shared:多租户

项目引用

从项目结构看项目引用

其他项目都项目引用modules(名称带有Management )、shared(名称带有shared)

 

modules内的product的项目引用关系

ProductManagement.Domain.Shared:没有项目引用

ProductManagement.Domain:项目引用 ProductManagement.Domain.Shared

ProductManagement.EntityFrameworkCore:项目引用 ProductManagement.Domain

ProductManagement.Application.Contracts:项目引用 ProductManagement.Domain.Shared

ProductManagement.HttpApi.Client:项目引用 ProductManagement.Application.Contracts

ProductManagement.HttpApi:项目引用 ProductManagement.Application.Contracts

ProductManagement.Web:项目引用 ProductManagement.HttpApi

ProductManagement.Application:项目引用 ProductManagement.Domain、ProductManagement.Application.Contracts

通信方式

说明:消息和RabbitMQ

参考:[Abp vNext微服务实践] - 服务通讯     [Abp vNext 源码分析] - 13. 本地事件总线与分布式事件总线 (Rabbit MQ)

动态 C# API 客户端

分布式 Event Bus--里面有说道ABP继承RabbitMQ

所有示例--里面有2个RabbitMQ的示例的

 

ABP可以动态创建C#API客户端代理来调用您的远程HTTP服务(REST API)。这样,您无需处理HttpClient其他低级详细信息即可调用远程服务并获得结果。

动态C#代理会自动为您处理以下内容;

  • 通过考虑HTTP方法,路由,查询字符串参数,请求有效负载和其他详细信息,将C#方法调用映射到远程服务器HTTP调用
  • 通过将访问令牌添加到HTTP标头来认证HTTP客户端。
  • 从JSON序列化和反序列化
  • 处理HTTP API版本控制
  • 相关性ID,当前租户ID和当前区域性添加到请求中。
  • 正确处理服务器发送的错误消息并引发适当的异常。

任何类型的.NET客户端都可以使用此系统来使用您的HTTP API。

 

模块层的ProductManagement.HttpApi.Client类库中的模块类ProductManagementHttpApiClientModule中

  • using Volo.Abp.Http.Client
  • 模块依赖typeof(AbpHttpClientModule)
  • 使用添加Http客户端代理方法:AddHttpClientProxies(typeof(ProductManagementApplicationContractsModule).Assembly, RemoteServiceName)

 

应用程序层

AuthServer.Host:登录认证服务

  • appsettings.json
    • RabbitMQ
      • Connections
      • EventBus,备注:模块类加载模块的DependsOn(typeof(AbpEventBusRabbitMqModule))时,AbpEventBusRabbitMqModule类会默认加载配置文件中的RabbitMQ:EventBus信息,反编译查看AbpEventBusRabbitMqModule的源码如下:
        public class AbpEventBusRabbitMqModule : AbpModule
        {
            public override void ConfigureServices(ServiceConfigurationContext context)
            {
                IConfiguration configuration = context.Services.GetConfiguration();
                Configure<AbpRabbitMqEventBusOptions>(configuration.GetSection("RabbitMQ:EventBus"));
            }
        
            public override void OnApplicationInitialization(ApplicationInitializationContext context)
            {
                context.ServiceProvider.GetRequiredService<RabbitMqDistributedEventBus>().Initialize();
            }
        }

         

PublicWebSite.Hos:产品、博客展示服务

  • appsettings.json
    • 登录服务:AuthServer:44399
    • 网关:RemoteServices:44397 PublicWebSiteGateway.Host(由PublicWebSite.Host应用程序用作后端)
  • AuthServerHostModule
    • options.Scope.Add("PublicWebSiteGateway");  //网关
    • options.Scope.Add("ProductService");  //产品微服务
    • options.Scope.Add("BloggingService"); //博客微服务

 

Program类读取配置文件:

  • AddJsonFile("appsettings.json")加载配置文件
    using System;
    using System.IO;
    using System.Linq;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Hosting;
    using Serilog;
    using Serilog.Events;
    using Serilog.Sinks.Elasticsearch;
    
    namespace AuthServer.Host
    {
        public class Program
        {
            public static int Main(string[] args)
            {
                //TODO: Temporary: it's not good to read appsettings.json here just to configure logging
                var configuration = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json")
                    .AddEnvironmentVariables()
                    .Build();
    
                Log.Logger = new LoggerConfiguration()
                    .MinimumLevel.Debug()
                    .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
                    .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
                    .Enrich.WithProperty("Application", "AuthServer")
                    .Enrich.FromLogContext()
                    .WriteTo.File("Logs/logs.txt")
                    .WriteTo.Elasticsearch(
                        new ElasticsearchSinkOptions(new Uri(configuration["ElasticSearch:Url"]))
                        {
                            AutoRegisterTemplate = true,
                            AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6,
                            IndexFormat = "msdemo-log-{0:yyyy.MM}"
                        })
                    .CreateLogger();
    
                try
                {
                    Log.Information("Starting AuthServer.Host.");
                    CreateHostBuilder(args).Build().Run();
                    return 0;
                }
                catch (Exception ex)
                {
                    Log.Fatal(ex, "AuthServer.Host terminated unexpectedly!");
                    return 1;
                }
                finally
                {
                    Log.CloseAndFlush();
                }
            }
    
            internal static IHostBuilder CreateHostBuilder(string[] args) =>
                Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    })
                    .UseAutofac()
                    .UseSerilog();
        }
    }
    View Code
  • 跟踪调试查看configuration=》Providers=》[0]=>Data,发现Data是一个字典类型的集合:System.Collections.Generic.IDictionary<string, string> 

 

网关层

PublicWebSiteGateway.Host:产品、博客网关

  • appsettings.json
    • 登录服务:AuthServer:44399 登录页
    • 路由:ReRoutes  
      • DownstreamPathTemplate(下游路径模板):productManagement?模块层?还是模板
      • DownstreamScheme(下游服务协议:http/https):
      • DownstreamHostAndPorts(下游服务地址):指定对应微服务
      • UpstreamPathTemplate(上游路径模板):
      • UpstreamHttpMethod(上游HTTP方法):[ "Put", "Delete", "Get", "Post" ]
  • PublicWebSiteGatewayHostModule模块类
    •  

                  //读取appsettings.json文件的登录配置   
                  context.Services.AddAuthentication("Bearer")
                      .AddIdentityServerAuthentication(options =>
                      {
                          options.Authority = configuration["AuthServer:Authority"];
                          options.ApiName = configuration["AuthServer:ApiName"];
                          options.RequireHttpsMetadata = false;
                      });    
      
                 //Ocelot网关
                  context.Services.AddOcelot(context.Services.GetConfiguration());
                  app.UseOcelot().Wait();

       

微服务层

ProductService.Host:产品微服务

  • appsettings.json
    • 登录服务:AuthServer:44399 =》登录页

BloggingService.Host:博客微服务

  • appsettings.json
    • 登录服务:AuthServer:44399 =》登录页
    • 网关:RemoteServices:44329  =》InternalGateway.Host  : 用于服务间通信(微服务之间的通信)
    • 认证:IdentityClients:4439 =》登录页
posted @ 2020-12-06 20:35  日积月累码农  阅读(1248)  评论(0编辑  收藏  举报