經(jīng)過一段時間的開發(fā)與測試,終于發(fā)布了Lms框架的第一個正式版本(1.0.0版本),并給出了lms框架的樣例項目lms.samples。本文通過對lms.samples的介紹,簡述如何通過lms框架快速的構(gòu)建一個微服務(wù)的業(yè)務(wù)框架,并進行應(yīng)用開發(fā)。
lms.samples項目基本介紹
lms.sample項目由三個獨立的微服務(wù)應(yīng)用模塊組成:account、stock、order和一個網(wǎng)關(guān)項目gateway構(gòu)成。
業(yè)務(wù)應(yīng)用模塊
每個獨立的微服務(wù)應(yīng)用采用模塊化設(shè)計,主要由如下幾部分組成:
- 主機(Host): 主要用于托管微服務(wù)應(yīng)用本身,主機通過引用應(yīng)用服務(wù)項目(應(yīng)用接口的實現(xiàn)),托管微服務(wù)應(yīng)用,通過托管應(yīng)用服務(wù),在主機啟動的過程中,向服務(wù)注冊中心注冊服務(wù)路由。
- 應(yīng)用接口層(Application.Contracts): 用于定義應(yīng)用服務(wù)接口,通過應(yīng)用接口,該微服務(wù)模塊與其他微服務(wù)模塊或是網(wǎng)關(guān)進行rpc通信的能力。在該項目中,除了定義應(yīng)用服務(wù)接口之前,一般還定義與該應(yīng)用接口相關(guān)的
DTO
對象。應(yīng)用接口除了被該微服務(wù)應(yīng)用項目引用,并實現(xiàn)應(yīng)用服務(wù)之前,還可以被網(wǎng)關(guān)或是其他微服務(wù)模塊引用。網(wǎng)關(guān)或是其他微服務(wù)項目通過應(yīng)用接口生成的代理與該微服務(wù)模塊通過rpc進行通信。
- 應(yīng)用服務(wù)層(Application): 應(yīng)用服務(wù)是該微服務(wù)定義的應(yīng)用接口的實現(xiàn)。應(yīng)用服務(wù)與DDD傳統(tǒng)分層架構(gòu)的應(yīng)用層的概念一致。主要負責外部通信與領(lǐng)域?qū)又g的協(xié)調(diào)。一般地,應(yīng)用服務(wù)進行業(yè)務(wù)流程控制,但是不包含業(yè)務(wù)邏輯的實現(xiàn)。
- 領(lǐng)域?qū)?Domain): 負責表達業(yè)務(wù)概念,業(yè)務(wù)狀態(tài)信息以及業(yè)務(wù)規(guī)則,是該微服務(wù)模塊的業(yè)務(wù)核心。一般地,在該層可以定義聚合根、實體、領(lǐng)域服務(wù)等對象。
- 領(lǐng)域共享層(Domain.Shared): 該層用于定義與領(lǐng)域?qū)ο笙嚓P(guān)的模型、實體等相關(guān)類型。不包含任何業(yè)務(wù)實現(xiàn),可以被其他微服務(wù)引用。
- 數(shù)據(jù)訪問(DataAccess)層: 該層一般用于封裝數(shù)據(jù)訪問相關(guān)的對象。例如:倉庫對象、
SqlHelper
、或是ORM相關(guān)的類型等。在lms.samples中,通過efcore實現(xiàn)數(shù)據(jù)的讀寫操作。
服務(wù)聚合與網(wǎng)關(guān)
lms框架不允許服務(wù)外部與微服務(wù)主機直接通信,應(yīng)用請求必須通過http請求到達網(wǎng)關(guān),網(wǎng)關(guān)通過lms提供的中間件解析到服務(wù)條目,并通過rpc與集群內(nèi)部的微服務(wù)進行通信。所以,如果服務(wù)需要與集群外部進行通信,那么,開發(fā)者定義的網(wǎng)關(guān)必須要引用各個微服務(wù)模塊的應(yīng)用接口層;以及必須要使用lms相關(guān)的中間件。
開發(fā)環(huán)境
- .net版本: 5.0.101
- lms版本: 1.0.0
- IDE: (1) visual studio 最新版 (2) Rider(推薦)
主機與應(yīng)用托管
主機的創(chuàng)建步驟
通過lms框架創(chuàng)建一個業(yè)務(wù)模塊非常方便,只需要通過如下4個步驟,就可以輕松的創(chuàng)建一個lms應(yīng)用業(yè)務(wù)模塊。
1.創(chuàng)建項目
創(chuàng)建控制臺應(yīng)用(Console Application)項目,并且引用Silky.Lms.NormHost
包。
dotnet add package Silky.Lms.NormHost --version 1.0.0
2.應(yīng)用程序入口與主機構(gòu)建
在main
方法中,通用.net的主機Host
構(gòu)建并注冊lms微服務(wù)。在注冊lms微服務(wù)時,需要指定lms啟動的依賴模塊。
一般地,如果開發(fā)者不需要額外依賴其他模塊,也無需在應(yīng)用啟動或停止時執(zhí)行方法,那么您可以直接指定NormHostModule
模塊。
public class Program
{
public static async Task Main(string[] args)
{
await CreateHostBuilder(args).Build().RunAsync();
}
private static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.RegisterLmsServicesNormHostModule>()
;
}
}
3.配置文件
lms框架支持yml
或是json
格式作為配置文件。通過appsettings.yml
對lms框架進行統(tǒng)一配置,通過appsettings.${Environment}.yml
對不同環(huán)境變量下的配置項進行設(shè)置。
開發(fā)者如果直接通過項目的方式啟動應(yīng)用,那么可以通過Properties/launchSettings.json
的environmentVariables.DOTNET_ENVIRONMENT
環(huán)境變量。如果通過docker-compose
的方式啟動應(yīng)用,那么可以通過.env
設(shè)置DOTNET_ENVIRONMENT
環(huán)境變量。
為保證配置文件有效,開發(fā)者需要顯式的將配置文件拷貝到項目生成目錄下。
4.引用應(yīng)用服務(wù)層和數(shù)據(jù)訪問層
一般地,主機項目需要引用該微服務(wù)模塊的應(yīng)用服務(wù)層和數(shù)據(jù)訪問層。只有主機引用應(yīng)用服務(wù)層,主機在啟動時,才會生成服務(wù)條目的路由,并且將服務(wù)路由注冊到服務(wù)注冊中心。
一個典型的主機項目文件如下所示:
Project Sdk="Microsoft.NET.Sdk">
PropertyGroup>
OutputType>Exe/OutputType>
TargetFramework>net5.0/TargetFramework>
/PropertyGroup>
ItemGroup>
PackageReference Include="Silky.Lms.NormHost" Version="$(LmsVersion)" />
/ItemGroup>
ItemGroup>
None Update="appsettings.yml">
CopyToOutputDirectory>Always/CopyToOutputDirectory>
/None>
None Update="appsettings.Production.yml">
CopyToOutputDirectory>Always/CopyToOutputDirectory>
/None>
None Update="appsettings.Development.yml">
CopyToOutputDirectory>Always/CopyToOutputDirectory>
/None>
/ItemGroup>
ItemGroup>
ProjectReference Include="..\Lms.Account.Application\Lms.Account.Application.csproj" />
ProjectReference Include="..\Lms.Account.EntityFrameworkCore\Lms.Account.EntityFrameworkCore.csproj" />
/ItemGroup>
/Project>
配置
一般地,一個微服務(wù)模塊的主機必須要配置:服務(wù)注冊中心、分布式鎖鏈接、分布式緩存地址、集群rpc通信token、數(shù)據(jù)庫鏈接地址等。
如果使用docker-compose來啟動和調(diào)試應(yīng)用的話,那么,rpc配置節(jié)點下的的host和port可以缺省,因為生成的每個容器的都有自己的地址和端口號。
如果直接通過項目的方式啟動和調(diào)試應(yīng)用的話,那么,必須要配置rpc節(jié)點下的port,每個微服務(wù)模塊的主機應(yīng)用有自己的端口號。
lms框架的必要配置如下所示:
rpc:
host: 0.0.0.0
rpcPort: 2201
token: ypjdYOzNd4FwENJiEARMLWwK0v7QUHPW
registrycenter:
connectionStrings: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183;127.0.0.1:2184,127.0.0.1:2185,127.0.0.1:2186 # 使用分號;來區(qū)分不同的服務(wù)注冊中心
registryCenterType: Zookeeper
distributedCache:
redis:
isEnabled: true
configuration: 127.0.0.1:6379,defaultDatabase=0
lock:
lockRedisConnection: 127.0.0.1:6379,defaultDatabase=1
connectionStrings:
default: server=127.0.0.1;port=3306;database=account;uid=root;pwd=qwe!P4ss;
應(yīng)用接口
應(yīng)用接口定義
一般地,在應(yīng)用接口層開發(fā)者需要安裝Silky.Lms.Rpc
包。如果該微服務(wù)模塊還涉及到分布式事務(wù),那么還需要安裝Silky.Lms.Transaction.Tcc
,當然,您也可以選擇在應(yīng)用接口層安裝Silky.Lms.Transaction
包,在應(yīng)用服務(wù)層安裝Silky.Lms.Transaction.Tcc
包。
- 開發(fā)者只需要在應(yīng)用接口通過
ServiceRouteAttribute
特性對應(yīng)用接口進行直接即可。
- Lms約定應(yīng)用接口應(yīng)當以
IXxxAppService
命名,這樣,服務(wù)條目生成的路由則會以api/xxx
形式生成。當然這并不是強制的。
- 每個應(yīng)用接口的方法都對應(yīng)著一個服務(wù)條目,服務(wù)條目的Id為: 方法的完全限定名 + 參數(shù)名
- 您可以在應(yīng)用接口層對方法的緩存、路由、服務(wù)治理、分布式事務(wù)進行相關(guān)配置。該部分內(nèi)容請參考官方文檔
- 網(wǎng)關(guān)或是其他模塊的微服務(wù)項目需要引用服務(wù)應(yīng)用接口項目或是通過nuget的方式安裝服務(wù)應(yīng)用接口生成的包。
[Governance(ProhibitExtranet = true)]
可以標識一個方法禁止與集群外部進行通信,通過網(wǎng)關(guān)也不會生成swagger文檔。
- 應(yīng)用接口方法生成的WebApi支持restful API風格。Lms支持通過方法的約定命名生成對應(yīng)http方法請求的WebApi。您當然開發(fā)者也可以通過
HttpMethodAttribute
特性對某個方法進行注解。
一個典型的應(yīng)用接口的定義
/// summary>
/// 賬號服務(wù)
/// /summary>
[ServiceRoute]
public interface IAccountAppService
{
/// summary>
/// 新增賬號
/// /summary>
/// param name="input">賬號信息/param>
/// returns>/returns>
TaskGetAccountOutput> Create(CreateAccountInput input);
/// summary>
/// 通過賬號名稱獲取賬號
/// /summary>
/// param name="name">賬號名稱/param>
/// returns>/returns>
[GetCachingIntercept("Account:Name:{0}")]
[HttpGet("{name:string}")]
TaskGetAccountOutput> GetAccountByName([CacheKey(0)] string name);
/// summary>
/// 通過Id獲取賬號信息
/// /summary>
/// param name="id">賬號Id/param>
/// returns>/returns>
[GetCachingIntercept("Account:Id:{0}")]
[HttpGet("{id:long}")]
TaskGetAccountOutput> GetAccountById([CacheKey(0)] long id);
/// summary>
/// 更新賬號信息
/// /summary>
/// param name="input">/param>
/// returns>/returns>
[UpdateCachingIntercept( "Account:Id:{0}")]
TaskGetAccountOutput> Update(UpdateAccountInput input);
/// summary>
/// 刪除賬號信息
/// /summary>
/// param name="id">賬號Id/param>
/// returns>/returns>
[RemoveCachingIntercept("GetAccountOutput","Account:Id:{0}")]
[HttpDelete("{id:long}")]
Task Delete([CacheKey(0)]long id);
/// summary>
/// 訂單扣款
/// /summary>
/// param name="input">/param>
/// returns>/returns>
[Governance(ProhibitExtranet = true)]
[RemoveCachingIntercept("GetAccountOutput","Account:Id:{0}")]
[Transaction]
Tasklong?> DeductBalance(DeductBalanceInput input);
}
應(yīng)用服務(wù)--應(yīng)用接口的實現(xiàn)
- 應(yīng)用服務(wù)層只需要引用應(yīng)用服務(wù)接口層以及領(lǐng)域服務(wù)層,并實現(xiàn)應(yīng)用接口相關(guān)的方法。
- 確保該微服務(wù)模塊的主機引用了該模塊的應(yīng)用服務(wù)層,這樣主機才能夠托管該應(yīng)用本身。
- 應(yīng)用服務(wù)層可以通過引用其他微服務(wù)模塊的應(yīng)用接口層項目(或是安裝nuget包,取決于開發(fā)團隊的項目管理方法),與其他微服務(wù)模塊進行rpc通信。
- 應(yīng)用服務(wù)層需要依賴領(lǐng)域服務(wù),通過調(diào)用領(lǐng)域服務(wù)的相關(guān)接口,實現(xiàn)該模塊的核心業(yè)務(wù)邏輯。
- DTO到實體對象或是實體對DTO對象的映射關(guān)系可以在該層指定映射關(guān)系。
一個典型的應(yīng)用服務(wù)的實現(xiàn)如下所示:
public class AccountAppService : IAccountAppService
{
private readonly IAccountDomainService _accountDomainService;
public AccountAppService(IAccountDomainService accountDomainService)
{
_accountDomainService = accountDomainService;
}
public async TaskGetAccountOutput> Create(CreateAccountInput input)
{
var account = input.MapToDomain.Accounts.Account>();
account = await _accountDomainService.Create(account);
return account.MapToGetAccountOutput>();
}
public async TaskGetAccountOutput> GetAccountByName(string name)
{
var account = await _accountDomainService.GetAccountByName(name);
return account.MapToGetAccountOutput>();
}
public async TaskGetAccountOutput> GetAccountById(long id)
{
var account = await _accountDomainService.GetAccountById(id);
return account.MapToGetAccountOutput>();
}
public async TaskGetAccountOutput> Update(UpdateAccountInput input)
{
var account = await _accountDomainService.Update(input);
return account.MapToGetAccountOutput>();
}
public Task Delete(long id)
{
return _accountDomainService.Delete(id);
}
[TccTransaction(ConfirmMethod = "DeductBalanceConfirm", CancelMethod = "DeductBalanceCancel")]
public async Tasklong?> DeductBalance(DeductBalanceInput input)
{
var account = await _accountDomainService.GetAccountById(input.AccountId);
if (input.OrderBalance > account.Balance)
{
throw new BusinessException("賬號余額不足");
}
return await _accountDomainService.DeductBalance(input, TccMethodType.Try);
}
public Task DeductBalanceConfirm(DeductBalanceInput input)
{
return _accountDomainService.DeductBalance(input, TccMethodType.Confirm);
}
public Task DeductBalanceCancel(DeductBalanceInput input)
{
return _accountDomainService.DeductBalance(input, TccMethodType.Cancel);
}
}
領(lǐng)域?qū)?-微服務(wù)的核心業(yè)務(wù)實現(xiàn)
- 領(lǐng)域?qū)邮窃撐⒎?wù)模塊核心業(yè)務(wù)處理的模塊,一般用于定于聚合根、實體、領(lǐng)域服務(wù)、倉儲等業(yè)務(wù)對象。
- 領(lǐng)域?qū)右迷撐⒎?wù)模塊的應(yīng)用接口層,方便使用dto對象。
- 領(lǐng)域?qū)涌梢酝ㄟ^引用其他微服務(wù)模塊的應(yīng)用接口層項目(或是安裝nuget包,取決于開發(fā)團隊的項目管理方法),與其他微服務(wù)模塊進行rpc通信。
- 領(lǐng)域服務(wù)必須要直接或間接繼承
ITransientDependency
接口,這樣,該領(lǐng)域服務(wù)才會被注入到ioc容器。
- lms.samples 項目使用TanvirArjel.EFCore.GenericRepository包實現(xiàn)數(shù)據(jù)的讀寫操作。
一個典型的領(lǐng)域服務(wù)的實現(xiàn)如下所示:
public class AccountDomainService : IAccountDomainService
{
private readonly IRepository _repository;
private readonly IDistributedCacheGetAccountOutput, string> _accountCache;
public AccountDomainService(IRepository repository,
IDistributedCacheGetAccountOutput, string> accountCache)
{
_repository = repository;
_accountCache = accountCache;
}
public async TaskAccount> Create(Account account)
{
var exsitAccountCount = await _repository.GetCountAsyncAccount>(p => p.Name == account.Name);
if (exsitAccountCount > 0)
{
throw new BusinessException($"已經(jīng)存在{account.Name}名稱的賬號");
}
exsitAccountCount = await _repository.GetCountAsyncAccount>(p => p.Email == account.Email);
if (exsitAccountCount > 0)
{
throw new BusinessException($"已經(jīng)存在{account.Email}Email的賬號");
}
await _repository.InsertAsyncAccount>(account);
return account;
}
public async TaskAccount> GetAccountByName(string name)
{
var accountEntry = _repository.GetQueryableAccount>().FirstOrDefault(p => p.Name == name);
if (accountEntry == null)
{
throw new BusinessException($"不存在名稱為{name}的賬號");
}
return accountEntry;
}
public async TaskAccount> GetAccountById(long id)
{
var accountEntry = _repository.GetQueryableAccount>().FirstOrDefault(p => p.Id == id);
if (accountEntry == null)
{
throw new BusinessException($"不存在Id為{id}的賬號");
}
return accountEntry;
}
public async TaskAccount> Update(UpdateAccountInput input)
{
var account = await GetAccountById(input.Id);
if (!account.Email.Equals(input.Email))
{
var exsitAccountCount = await _repository.GetCountAsyncAccount>(p => p.Email == input.Email);
if (exsitAccountCount > 0)
{
throw new BusinessException($"系統(tǒng)中已經(jīng)存在Email為{input.Email}的賬號");
}
}
if (!account.Name.Equals(input.Name))
{
var exsitAccountCount = await _repository.GetCountAsyncAccount>(p => p.Name == input.Name);
if (exsitAccountCount > 0)
{
throw new BusinessException($"系統(tǒng)中已經(jīng)存在Name為{input.Name}的賬號");
}
}
await _accountCache.RemoveAsync($"Account:Name:{account.Name}");
account = input.MapTo(account);
await _repository.UpdateAsync(account);
return account;
}
public async Task Delete(long id)
{
var account = await GetAccountById(id);
await _accountCache.RemoveAsync($"Account:Name:{account.Name}");
await _repository.DeleteAsync(account);
}
public async Tasklong?> DeductBalance(DeductBalanceInput input, TccMethodType tccMethodType)
{
var account = await GetAccountById(input.AccountId);
var trans = await _repository.BeginTransactionAsync();
BalanceRecord balanceRecord = null;
switch (tccMethodType)
{
case TccMethodType.Try:
account.Balance -= input.OrderBalance;
account.LockBalance += input.OrderBalance;
balanceRecord = new BalanceRecord()
{
OrderBalance = input.OrderBalance,
OrderId = input.OrderId,
PayStatus = PayStatus.NoPay
};
await _repository.InsertAsync(balanceRecord);
RpcContext.GetContext().SetAttachment("balanceRecordId",balanceRecord.Id);
break;
case TccMethodType.Confirm:
account.LockBalance -= input.OrderBalance;
var balanceRecordId1 = RpcContext.GetContext().GetAttachment("orderBalanceId")?.Tolong>();
if (balanceRecordId1.HasValue)
{
balanceRecord = await _repository.GetByIdAsyncBalanceRecord>(balanceRecordId1.Value);
balanceRecord.PayStatus = PayStatus.Payed;
await _repository.UpdateAsync(balanceRecord);
}
break;
case TccMethodType.Cancel:
account.Balance += input.OrderBalance;
account.LockBalance -= input.OrderBalance;
var balanceRecordId2 = RpcContext.GetContext().GetAttachment("orderBalanceId")?.Tolong>();
if (balanceRecordId2.HasValue)
{
balanceRecord = await _repository.GetByIdAsyncBalanceRecord>(balanceRecordId2.Value);
balanceRecord.PayStatus = PayStatus.Cancel;
await _repository.UpdateAsync(balanceRecord);
}
break;
}
await _repository.UpdateAsync(account);
await trans.CommitAsync();
await _accountCache.RemoveAsync($"Account:Name:{account.Name}");
return balanceRecord?.Id;
}
}
數(shù)據(jù)訪問(EntityFrameworkCore)--通過efcore實現(xiàn)數(shù)據(jù)讀寫
- lms.samples項目使用orm框架efcore進行數(shù)據(jù)讀寫。
- lms提供了
IConfigureService
,通過繼承該接口即可使用IServiceCollection
的實例指定數(shù)據(jù)上下文對象和注冊倉庫服務(wù)。
public class EfCoreConfigureService : IConfigureService
{
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddDbContextOrderDbContext>(opt =>
opt.UseMySql(configuration.GetConnectionString("Default"),
ServerVersion.AutoDetect(configuration.GetConnectionString("Default"))))
.AddGenericRepositoryOrderDbContext>(ServiceLifetime.Transient)
;
}
public int Order { get; } = 1;
}
3.主機項目需要顯式的引用該項目,只有這樣,該項目的ConfigureServices
才會被調(diào)用。
4.數(shù)據(jù)遷移,請參考
應(yīng)用啟動與調(diào)試
獲取源碼
1.使用git 克隆lms項目源代碼,lms.samples存放在samples
目錄下
# github
git clone https://github.com/liuhll/lms.git
# gitee
git clone https://gitee.com/liuhll2/lms.git
必要的前提
- 服務(wù)注冊中心
zookeeper
- 緩存服務(wù)
redis
- mysql數(shù)據(jù)庫
如果您電腦已經(jīng)安裝了docker以及docker-compose命令,那么您只需要進入samples\docker-compose\infrastr
目錄下,打開命令行工作,執(zhí)行如下命令就可以自動安裝zookeeper
、redis
、mysql
等服務(wù):
docker-compose -f .\docker-compose.mysql.yml -f .\docker-compose.redis.yml -f .\docker-compose.zookeeper.yml up -d
數(shù)據(jù)庫遷移
需要分別進入到各個微服務(wù)模塊下的EntityFrameworkCore
項目(例如:),執(zhí)行如下命令:
dotnet ef database update
例如: 需要遷移account模塊的數(shù)據(jù)庫如下所示:
order模塊和stock模塊與account模塊一致,在服務(wù)運行前都需要通過數(shù)據(jù)庫遷移命令生成相關(guān)數(shù)據(jù)庫。
- 數(shù)據(jù)庫遷移指定數(shù)據(jù)庫連接地址默認指定的是
appsettings.Development.yml
中配置的,您可以通過修改該配置文件中的connectionStrings.default
配置項來指定自己的數(shù)據(jù)庫服務(wù)地址。
- 如果沒有
dotnet ef
命令,則需要通過dotnet tool install --global dotnet-ef
安裝ef工具,請[參考] (https://docs.microsoft.com/zh-cn/ef/core/get-started/overview/install)
以項目的方式啟動和調(diào)試
使用visual studio作為開發(fā)工具
進入到samples目錄下,使用visual studio打開lms.samples.sln
解決方案,將項目設(shè)置為多啟動項目,并將網(wǎng)關(guān)和各個模塊的微服務(wù)主機設(shè)置為啟動項目,如下圖:
設(shè)置完成后直接啟動即可。
使用rider作為開發(fā)工具進入到samples目錄下,使用rider打開lms.samples.sln
解決方案,打開各個微服務(wù)模塊下的Properties/launchSettings.json
,點擊圖中綠色的箭頭即可啟動項目。
啟動網(wǎng)關(guān)項目后,可以看到應(yīng)用接口的服務(wù)條目生成的swagger api文檔 http://localhost:5000/swagger。
默認的環(huán)境變量為: Development
,如果需要修改環(huán)境變量的話,可以通過Properties/launchSettings.json
下的environmentVariables
節(jié)點修改相關(guān)環(huán)境變量,請參考在 ASP.NET Core 中使用多個環(huán)境。
數(shù)據(jù)庫連接、服務(wù)注冊中心地址、以及redis緩存地址和分布式鎖連接等配置項可以通過修改appsettings.Development.yml
配置項自定義指定。
以docker-compose的方式啟動和調(diào)試
進入到samples目錄下,使用visual studio打開lms.samples.dockercompose.sln
解決方案,將docker-compose設(shè)置為啟動項目,即可啟動和調(diào)式。
應(yīng)用啟動成功后,打開: http://127.0.0.1/swagger,即可看到swagger api文檔
以docker-compose的方式啟動和調(diào)試,則指定的環(huán)境變量為:ContainerDev
數(shù)據(jù)庫連接、服務(wù)注冊中心地址、以及redis緩存地址和分布式鎖連接等配置項可以通過修改appsettings.ContainerDev.yml
配置項自定義指定,配置的服務(wù)連接地址不允許為: 127.0.0.1
或是localhost
測試和調(diào)式
服務(wù)啟動成功后,您可以通過寫入/api/account-post
接口和/api/product-post
新增賬號和產(chǎn)品,然后通過/api/order-post
接口進行測試和調(diào)式。
開源地址
github: https://github.com/liuhll/lms
gitee: https://gitee.com/liuhll2/lms
到此這篇關(guān)于通過lms.samples熟悉lms微服務(wù)框架的使用的文章就介紹到這了,更多相關(guān)lms微服務(wù)框架內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Java從單體架構(gòu)升級到微服務(wù)要注意的一些問題
- 詳解Java 微服務(wù)架構(gòu)
- 了解java架構(gòu)之微服務(wù)架構(gòu)—雪崩效應(yīng)
- golang 實現(xiàn)一個restful微服務(wù)的操作
- SpringCloud搭建netflix-eureka微服務(wù)集群的過程詳解
- SpringCloud讓微服務(wù)實現(xiàn)指定程序調(diào)用
- Spring Cloud Stream微服務(wù)消息框架原理及實例解析
- 詳解多云架構(gòu)下的JAVA微服務(wù)技術(shù)解析