zoukankan      html  css  js  c++  java
  • 个人解读《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 =》登录页
  • 相关阅读:
    HDU4405(期望DP)
    hdu4165(简单递推,实则卡特兰数的应用)
    hdu4576(概率DP)
    期望DP(2013山东省赛)
    Nim游戏及其相关拓展
    nginx ubuntu环境下配置 path_info
    iOS 瀑布流的简单实现 UICollectionView
    ThPullRefresh (Swift 版)下拉上拉刷新
    用php搭建博客系统-待续
    面试收录-php面试题
  • 原文地址:https://www.cnblogs.com/qingyunye/p/14094177.html
Copyright © 2011-2022 走看看