ABP VNext從單體切換到微服務

注:此處的微服務只考慮服務部分,不考慮內外層網關、認證等。git

ABP VNext從單體切換到微服務,提供了至關大的便利性,對於各模塊內部不要作任何調整,僅須要調整承載體便可。c#

ABP can help you in that point by offerring a microservice-compatible, strict module architecture where your module is splitted into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application.api

分層架構

  1. ABP VNext自身提供的分層方式以下圖,核心部分是Application、Domain與EntityFrameworkCore層,至於HttpApi.Client與HttpApi都是屬於將應用去承載到其餘系統之上的。

圖片

  1. Controller層在ABP VNext中被削弱了,VNext提供了將Application提供動態Controller,因此可能習慣了將部分邏輯寫在控制器中的會有些唐突,但理解就行。

圖片

規劃層次結構

  1. 新建空文件夾,取名隨意(本次取名GravelService),用於存放總體項目。
  2. 在上一步的空文件夾內新建空白解決方案,能夠用VS去生成或是按照dotnet的命令生成。

圖片

  1. 習慣上按照ABP VNext給定的微服務Demo中的格式建立三個文件夾,思路清晰。固然提供的微服務Demo還有更多文件夾,可是此次只關注這三個。

圖片

增長三個模塊

  1. 設計三個限界上下文並繪製上下文映射。依照常見的訂單、產品與客戶劃分紅三個限界上下文。並規劃好訂單做爲下游依賴產品與客戶做爲的上游。

圖片

  1. 從官網直接下載三個模塊,或是按照命令行去生成(前提是已經安裝了ABP CLI),不管哪一種方式,確保準備好就行,依照模塊化思想,將其存到modules文件夾下。

圖片

  1. 如本次準備了三個模塊Product,Order,Customer,依照實際須要,能夠去精簡一下內部文件,此處各模塊內部我只留着src和test文件夾。

圖片

  1. 對於customer模塊的src內部,具體生成的文件夾以下,對於其中的HttpApi、HttpApi.Client及MongoDB,我採起了剔除,無需這部分(在稍後的承載體中有同等功能)。

圖片

清理以後變得簡簡單單的。架構

圖片

對於test內部,一樣採起剔除無需的HttpApi.CLient、MongoDB文件夾(注:此處的無需只是針對我而言,若是有須要仍是留着吧)。app

圖片

清理以後,層次劃分變得簡簡單單的。async

圖片

  1. 改造下各模塊內給定的Sample案例,改形成各模塊命名開頭,方便加以區分。以Customer模塊爲例,將自帶的Sample案例改名成Customer,僅做該項改動。

圖片

模擬服務調用

  1. 對於Order與Product模塊內增長一個下游訪問上游服務的鏈路,方便驗證從單體跨越到微服務,底層服務的無需任何改動。對於下游訪問上游服務的調用形式,瞭解到的有兩種方式。
  • 當前上下文的應用層直接依賴其餘上下文的應用服務;
  • 當前上下文設定出防腐層(在限界上下文間增長一層隔離,方便保證依賴限界上下文存在變更時只需更改隔離層),在防腐層的實現中去依賴或遠程調用其餘上下文的應用服務;
  1. 我我的傾向於增長防腐層,雖然在VNext中並沒有相關說法。具體使用時,在領域層或應用層增長防腐層接口,及在EF Core層給與防腐層實現,此時的EF Core層,更應該改名爲基礎設施層,而不僅僅是做爲資源庫的形式。

圖片

  1. 在Order中Domain層增長ServiceClients文件夾用於存放防腐層接口,而在EntityFrameworkCore層增長ServiceClients文件夾用於存放防腐層實現。
  • 在防腐層接口中增長IProductServiceClient。
public interface IProductServiceClient : ITransientDependency
{
    Task<int> GetProductId();
}
  • 在防腐層實現中增長ProductServiceClient。
  • 在Order中的EntityFrameworkCore層引用Product模塊內的Application.Contracts層。
  • 依賴ProductAppService並完成調用。
public class ProductServiceClient : IProductServiceClient
{
    private readonly IProductAppService _productAppService;
    public ProductServiceClient(IProductAppService productAppService)
    {
        _productAppService = productAppService;
    }
    public async Task<int> GetProductId()
    {
        var productDto = await _productAppService.GetAsync();
        return productDto.Value;
    }
}
  • 在OrderAppService中依賴防腐層接口,並完成調用。
public class OrderAppService : OrderManagementAppService,   IOrderAppService
{
    private readonly IProductServiceClient _productServiceClient;
    public OrderAppService(IProductServiceClient productServiceClient)
    {
        _productServiceClient = productServiceClient;
    }
    public async Task<OrderDto> GetAsync()
    {
        var productId = await _productServiceClient.GetProductId();
        ...
    }
}
  1. 這樣一來,在防腐層實現中即可以使用到Product上下文的應用服務了,對於這個應用服務的請求是當前進程內的仍是進程間的,由具體的承載方式而決定。

圖片

大單體承載

將依照以下圖,將三個模塊承載到GravelService.Host上。ide

圖片

  1. 新建一個GravelService.Host的項目,採用WebApi類型便可。存放到microservices文件夾下,這樣方便理解整個層級劃分。

圖片

  1. 其次依賴一些基本的Nuget包,諸如ABP自身的及方便展現Api的Swagger。本次不考慮實體的建立,也就不考慮EF Core包的依賴了。
  • Volo.Abp
  • Volo.Abp.AspNetCore.MultiTenancy
  • Volo.Abp.AspNetCore.Mvc
  • Volo.Abp.Autofac
  • Swashbuckle.AspNetCore
  1. 引用各模塊內的Application層及EntityFrameworkCore層。模仿着給定的微服務Demo,完成一波CV操做。增長一個類出來承擔着服務與中間件的配置。

圖片

  1. 在其中依賴引用的各Application層及EntityFrameworkCore層中的Module,這樣一來模塊依賴就搞定了。
[DependsOn(
    typeof(AbpAutofacModule),
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpAspNetCoreMultiTenancyModule),
    typeof(CustomerManagementApplicationModule),
    typeof(CustomerManagementEntityFrameworkCoreModule),
    typeof(OrderManagementApplicationModule),
    typeof(OrderManagementEntityFrameworkCoreModule),
    typeof(ProductManagementApplicationModule),
    typeof(ProductManagementEntityFrameworkCoreModule)
   )]
public class GravelServiceHostModule : AbpModule
{
  ...
}
  1. 增長服務配置,將各模塊中的應用服務動態轉換成Api控制器。
Configure<AbpAspNetCoreMvcOptions>(options =>
{
    options.ConventionalControllers
        .Create(typeof(CustomerManagementApplicationModule).Assembly,       
        opts =>
        {
            opts.RootPath = "CustomerManagement";
        })
        .Create(typeof(OrderManagementApplicationModule).Assembly, 
        opts =>
        {
            opts.RootPath = "OrderManagement";
        })
        .Create(typeof(ProductManagementApplicationModule).Assembly, 
        opts =>
        {
            opts.RootPath = "ProductManagement";
        });
});
  1. 而後,啓動便可,全部模塊中的接口都承載到了該承載體中。

圖片

  1. 經過訪問Order的api/OrderManagement/order接口得到返回的9527,也就驗證了,防腐層內去訪問Product上下文的應用服務。

圖片

此時是在同一進程內,使用到的是ProductAppService的具體實現,斷點查看也可看出當前進程內的請求,依賴其餘上下文服務的應用服務爲ApplicationServiceProxy。模塊化

圖片

多服務承載

依照以下圖開始切換承載模式,只更改承載體,將一個大的承載體切分紅各上下文獨自承載體。微服務

圖片

  1. 新建三個和GravelService.Host同等的WebApi項目。在GravelService.Host上裁剪便可,每一個獨立的承載體只擁有自身的上下文。

圖片

  1. 依據上下文映射關係,對處於下游的Order承載體增長對上游Product的依賴,在Order承載體中增長對Product模塊中Application.Contracts層的依賴。並在服務配置中完成依賴(第7行)。
[DependsOn(
    typeof(AbpAutofacModule),
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpAspNetCoreMultiTenancyModule),
    typeof(OrderManagementApplicationModule),
    typeof(OrderManagementEntityFrameworkCoreModule),
    typeof(ProductManagementApplicationContractsModule)
    )]
public class OrderServiceHostModule : AbpModule
{
...
}
  1. 配置遠程服務代理,在服務配置中設置從Order承載體到Product承載體的遠程服務請求。在Order承載體中增長Volo.Abp.Http.Client包並在服務配置中完成依賴。
[DependsOn(
    ...
    typeof(AbpHttpClientModule),
    ...
    )]
public class OrderServiceHostModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        ...                       
        context.Services.AddHttpClientProxies(         typeof(ProductManagementApplicationContractsModule).Assembly);
        ...
    }
}
  1. 在配置源appsettings文件中加入對Product承載體的遠程調用地址
 {
  "RemoteServices": {
    "Default": {
      "BaseUrl": "http://localhost:57687"
    }
}
  1. 更改項目配置,啓動多個文件,一併啓動三個獨立承載體,再次調用Order中的Get請求,一樣得到了從Product上下文的應用服務中的數據

圖片

  1. 此次採用的不一樣進程間的承載方式,經過防腐層,而後經ABP提供的Http代理服務調用Product承載體,能夠斷點查看當前在防腐層中的AppService類型,已經再也不是直接使用ProductAppService了。

圖片

真香

從大單體承載切換多服務承載,Modules部分不須要作任何更改,着實方便。至於內部的遠程調用,自己ABP VNext還存在一些問題像相似集合的Get請求在3.1的版本中才作了修復,可是這絲絕不影響這一巨人的前行。命令行

碼雲倉庫

2020-09-26,望技術有成後能回來看見本身的腳步

相關文章
相關標籤/搜索