上一篇我们基础服务初步搭建完毕,接下来我们整一下认证和网关。

搭建认证服务

认证服务的话,ABP CLI生成的所有模板都包括了一个AuthServer。我们直接生成模板然后微调一下就可以直接用了。

abp new FunShow -t app --tiered

使用命令创建模板后,我们可以找到一个AuthServer。把项目移动到Apps目录下,然后我们开始改造一下这个项目。
首先修改项目文件的引用配置
修改EFCore项目引用为AdministrationService.EntityFrameworkCore和IdentityService.EntityFrameworkCore,
然后添加Shared.Localization和Shared.Hosting.AspNetCore项目引用,别的基本不用怎么修改,完整项目配置为:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <Import Project="..\..\..\..\common.props" />

  <PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<UserSecretsId>b83bc18b-a6ca-4e2d-a827-26ffaff35dce</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..\..\..</DockerfileContext>
</PropertyGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.5" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />
</ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="7.0.0" />
<PackageReference Include="Volo.Abp.EventBus.RabbitMQ" Version="7.0.0" />
<PackageReference Include="Volo.Abp.BackgroundJobs.RabbitMQ" Version="7.0.0" />
<PackageReference Include="Volo.Abp.Account.Web.OpenIddict" Version="7.0.0" />
<PackageReference Include="Volo.Abp.Account.Application" Version="7.0.0" />
<PackageReference Include="Volo.Abp.Account.HttpApi" Version="7.0.0" />
</ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\services\administration\src\FunShow.AdministrationService.EntityFrameworkCore\FunShow.AdministrationService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\services\identity\src\FunShow.IdentityService.EntityFrameworkCore\FunShow.IdentityService.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\..\..\shared\FunShow.Shared.Hosting.AspNetCore\FunShow.Shared.Hosting.AspNetCore.csproj" />
<ProjectReference Include="..\..\..\..\shared\FunShow.Shared.Localization\FunShow.Shared.Localization.csproj" />
</ItemGroup> <ItemGroup>
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />
</ItemGroup> <ItemGroup>
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup> </Project>

然后修改Program文件,主要是日志配置修改一下,别的不用改动

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using FunShow.Shared.Hosting.AspNetCore;
using Serilog; namespace FunShow.AuthServer; public class Program
{
public async static Task<int> Main(string[] args)
{
var assemblyName = typeof(Program).Assembly.GetName().Name; SerilogConfigurationHelper.Configure(assemblyName); try
{
Log.Information($"Starting {assemblyName}.");
var builder = WebApplication.CreateBuilder(args);
builder.Host
.AddAppSettingsSecretsJson()
.UseAutofac()
.UseSerilog();
await builder.AddApplicationAsync<FunShowAuthServerModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, $"{assemblyName} terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
}

修改module.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using FunShow.AdministrationService.EntityFrameworkCore;
using FunShow.IdentityService.EntityFrameworkCore;
using FunShow.Shared.Hosting.AspNetCore;
using Prometheus;
using StackExchange.Redis;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.Auditing;
using Volo.Abp.BackgroundJobs.RabbitMQ;
using Volo.Abp.Caching;
using Volo.Abp.Caching.StackExchangeRedis;
using Volo.Abp.Emailing;
using Volo.Abp.EventBus.RabbitMq;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict;
using Volo.Abp.UI.Navigation.Urls;
using Volo.Abp.VirtualFileSystem;
using Microsoft.AspNetCore.HttpOverrides;
using FunShow.Shared.Localization; namespace FunShow.AuthServer; [DependsOn(
typeof(AbpCachingStackExchangeRedisModule),
typeof(AbpEventBusRabbitMqModule),
typeof(AbpBackgroundJobsRabbitMqModule),
typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
typeof(AbpAccountWebOpenIddictModule),
typeof(AbpAccountApplicationModule),
typeof(AbpAccountHttpApiModule),
typeof(AdministrationServiceEntityFrameworkCoreModule),
typeof(IdentityServiceEntityFrameworkCoreModule),
typeof(FunShowSharedHostingAspNetCoreModule),
typeof(FunShowSharedLocalizationModule)
)]
public class FunShowAuthServerModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration(); PreConfigure<OpenIddictBuilder>(builder =>
{
builder.AddValidation(options =>
{
options.AddAudiences("AccountService");
options.UseLocalServer();
options.UseAspNetCore();
});
});
if (!hostingEnvironment.IsDevelopment())
{
PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
options.AddDevelopmentEncryptionAndSigningCertificate = false;
}); PreConfigure<OpenIddictServerBuilder>(builder =>
{
builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration));
builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration));
});
}
} public override void ConfigureServices(ServiceConfigurationContext context)
{
//You can disable this setting in production to avoid any potential security risks.
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true; var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration(); ConfigureBundles();
ConfigureSwagger(context, configuration);
ConfigureSameSiteCookiePolicy(context);
ConfigureExternalProviders(context); Configure<AbpMultiTenancyOptions>(options =>
{
options.IsEnabled = true;
}); Configure<AbpAuditingOptions>(options =>
{
options.ApplicationName = "AuthServer";
}); Configure<AppUrlOptions>(options =>
{
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));
}); Configure<AbpDistributedCacheOptions>(options =>
{
options.KeyPrefix = "FunShow:";
}); var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("FunShow");
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);
dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "FunShow-Protection-Keys"); context.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(
configuration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.Trim().RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
}); #if DEBUG
context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>());
#endif if (hostingEnvironment.IsDevelopment())
{
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.ReplaceEmbeddedByPhysical<FunShowSharedLocalizationModule>(Path.Combine(
hostingEnvironment.ContentRootPath,
$"..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}shared{Path.DirectorySeparatorChar}FunShow.Shared.Localization"));
});
}
} public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment(); var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>(); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
} app.UseAbpRequestLocalization(); if (!env.IsDevelopment())
{
app.UseErrorPage();
}
var forwardOptions = new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
RequireHeaderSymmetry = false
}; forwardOptions.KnownNetworks.Clear();
forwardOptions.KnownProxies.Clear(); // ref: https://github.com/aspnet/Docs/issues/2384
app.UseForwardedHeaders(forwardOptions); app.UseCorrelationId();
app.UseAbpSecurityHeaders();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseCookiePolicy();
app.UseHttpMetrics();
app.UseAuthentication();
app.UseAbpOpenIddictValidation();
app.UseAbpSerilogEnrichers();
app.UseUnitOfWork();
app.UseAuthorization();
app.UseSwagger();
app.UseAbpSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Account Service API");
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);
});
app.UseAuditing();
app.UseConfiguredEndpoints(endpoints =>
{
endpoints.MapMetrics();
});
} private void ConfigureBundles()
{
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
LeptonXLiteThemeBundles.Styles.Global,
bundle =>
{
bundle.AddFiles("/global-styles.css");
}
);
});
} private void ConfigureExternalProviders(ServiceConfigurationContext context)
{
context.Services.AddAuthentication();
} private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration)
{
var fileName = "authserver.pfx";
var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED";
var file = Path.Combine(hostingEnv.ContentRootPath, fileName); if (!File.Exists(file))
{
throw new FileNotFoundException($"Signing Certificate couldn't found: {file}");
} return new X509Certificate2(file, passPhrase);
} private void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration)
{
SwaggerConfigurationHelper.ConfigureWithAuth(
context: context,
authority: configuration["AuthServer:Authority"],
scopes: new Dictionary<string, string> {
/* Requested scopes for authorization code request and descriptions for swagger UI only */
{ "AccountService", "Account Service API" }
},
apiTitle: "Account Service API"
);
} private void ConfigureSameSiteCookiePolicy(ServiceConfigurationContext context)
{
context.Services.AddSameSiteCookiePolicy();
}
}

最后修改配置文件

{
"App": {
"SelfUrl": "https://localhost:44322",
"CorsOrigins": "http://localhost:4200,http://localhost:9527,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361",
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307,https://localhost:44321,http://localhost:9527"
},
"AuthServer": {
"Authority": "https://localhost:44322",
"RequireHttpsMetadata": "true",
"SwaggerClientId": "WebGateway_Swagger"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"AdministrationService": "Host=localhost;Port=5432;User ID=postgres;password=myPassw0rd;Pooling=true;Database=FunShow_Administration;",
"IdentityService": "Host=localhost;Port=5432;User ID=postgres;password=myPassw0rd;Pooling=true;Database=FunShow_Identity;"
},
"StringEncryption": {
"DefaultPassPhrase": "fCrJICTG3WoyissG"
},
"Redis": {
"Configuration": "localhost:6379"
},
"RabbitMQ": {
"Connections": {
"Default": {
"HostName": "localhost"
}
},
"EventBus": {
"ClientName": "FunShow_AuthServer",
"ExchangeName": "FunShow"
}
},
"ElasticSearch": {
"Url": "http://localhost:9200"
}
}

这样我们认证服务即修改完成。

搭建网关服务

网关服务我们直接新建一个空asp.net core项目。
然后只需要添加一个我们的Shared.Hosting.Gateways项目引用即可。

<Project Sdk="Microsoft.NET.Sdk.Web">

  <Import Project="..\..\..\..\common.props" />

  <PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\shared\FunShow.Shared.Hosting.Gateways\FunShow.Shared.Hosting.Gateways.csproj" />
</ItemGroup> <ItemGroup>
<Compile Remove="Logs\**" />
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
</ItemGroup> </Project>

修改Program.cs

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using FunShow.Shared.Hosting.AspNetCore;
using Serilog; namespace FunShow.WebGateway; public class Program
{
public async static Task<int> Main(string[] args)
{
var assemblyName = typeof(Program).Assembly.GetName().Name; SerilogConfigurationHelper.Configure(assemblyName); try
{
Log.Information($"Starting {assemblyName}.");
var builder = WebApplication.CreateBuilder(args);
builder.Host
.AddAppSettingsSecretsJson()
.AddYarpJson()
.UseAutofac()
.UseSerilog();
await builder.AddApplicationAsync<FunShowWebGatewayModule>();
var app = builder.Build();
await app.InitializeApplicationAsync();
await app.RunAsync();
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, $"{assemblyName} terminated unexpectedly!");
return 1;
}
finally
{
Log.CloseAndFlush();
}
}
}

这里和认证服务基本一致,就是多了一个AddYarpJson()来添加我们的yarp的配置文件。
在目录下新建yarp.json文件,添加我们的yarp配置内容。配置集群和路由如下:

{
"ReverseProxy": {
"Routes": {
"Account Service": {
"ClusterId": "accountCluster",
"Match": {
"Path": "/api/account/{**everything}"
}
},
"Identity Service": {
"ClusterId": "identityCluster",
"Match": {
"Path": "/api/identity/{**everything}"
}
},
"Administration Service": {
"ClusterId": "administrationCluster",
"Match": {
"Path": "/api/abp/{**everything}"
}
},
"Logging Service": {
"ClusterId": "loggingCluster",
"Match": {
"Path": "/api/LoggingService/{**everything}"
}
},
"feature-management-route": {
"ClusterId": "feature-management-cluster",
"Match": {
"Path": "/api/feature-management/{**everything}"
}
},
"permission-management-route": {
"ClusterId": "permission-management-cluster",
"Match": {
"Path": "/api/permission-management/{**everything}"
}
},
"setting-management-route": {
"ClusterId": "setting-management-cluster",
"Match": {
"Path": "/api/setting-management/{**everything}"
}
}
},
"Clusters": {
"accountCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44322"
}
}
},
"identityCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44388"
}
}
},
"administrationCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
},
"loggingCluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:45124"
}
}
},
"feature-management-cluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
},
"permission-management-cluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
},
"setting-management-cluster": {
"Destinations": {
"destination1": {
"Address": "https://localhost:44367"
}
}
}
}
}
}

在appsettings.json文件添加我们认证服务的地址

{
"App": {
"SelfUrl": "https://localhost:44325",
"CorsOrigins": "http://localhost:4200,https://localhost:44307,http://localhost:9527"
},
"AuthServer": {
"Authority": "https://localhost:44322",
"RequireHttpsMetadata": "true",
"SwaggerClientId": "WebGateway_Swagger"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"Redis": {
"Configuration": "localhost:6379"
},
"ElasticSearch": {
"Url": "http://localhost:9200"
}
}

最后我们添加FunShowWebGatewayModule文件。配置我们yarp的服务。

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using FunShow.Shared.Hosting.AspNetCore;
using FunShow.Shared.Hosting.Gateways;
using Volo.Abp;
using Volo.Abp.Modularity; namespace FunShow.WebGateway; [DependsOn(
typeof(FunShowSharedHostingGatewaysModule)
)]
public class FunShowWebGatewayModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
// Enable if you need hosting environment
// var hostingEnvironment = context.Services.GetHostingEnvironment();
var configuration = context.Services.GetConfiguration();
var hostingEnvironment = context.Services.GetHostingEnvironment(); SwaggerConfigurationHelper.ConfigureWithAuth(
context: context,
authority: configuration["AuthServer:Authority"],
scopes: new
Dictionary<string, string> /* Requested scopes for authorization code request and descriptions for swagger UI only */ {
{ "AccountService", "Account Service API" },
{ "IdentityService", "Identity Service API" },
{ "AdministrationService", "Administration Service API" },
{ "LoggingService", "Logging Service API" }
},
apiTitle: "Web Gateway API"
); context.Services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder
.WithOrigins(
configuration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.Trim().RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
} public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment(); if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCorrelationId();
app.UseAbpSerilogEnrichers();
app.UseCors();
app.UseSwaggerUIWithYarp(context); app.UseRewriter(new RewriteOptions()
// Regex for "", "/" and "" (whitespace)
.AddRedirect("^(|\\|\\s+)$", "/swagger")); app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapReverseProxy();
});
}
}

UseSwaggerUIWithYarp是从我们Yarp配置文件中读取服务信息去构造swagger路由配置。
好了,到这我们认证服务和网关服务也搭建完毕,下一篇我们开始迁移数据库。

ABP微服务系列学习-搭建自己的微服务结构(三)的更多相关文章

  1. springcloud微服务架构搭建

    SpringCloud微服务框架搭建 一.微服务架构 1.1什么是分布式 不同模块部署在不同服务器上 作用:分布式解决网站高并发带来问题 1.2什么是集群 多台服务器部署相同应用构成一个集群 作用:通 ...

  2. SprngCloud微服务框架搭建(一)

    参照来源 :https://blog.csdn.net/forezp/article/details/70148833 1.简介 目前来说,SpringCloud是比较完整的微服务解决方案框架.不像其 ...

  3. Spring Cloud 微服务中搭建 OAuth2.0 认证授权服务

    在使用 Spring Cloud 体系来构建微服务的过程中,用户请求是通过网关(ZUUL 或 Spring APIGateway)以 HTTP 协议来传输信息,API 网关将自己注册为 Eureka ...

  4. 【spring colud】spring cloud微服务项目搭建【spring boot2.0】

    spring cloud微服务项目搭建 =================================== 示例版本: 1.spring boot 2.0版本 2.开发工具 IntellJ IDE ...

  5. 简单Spring Cloud 微服务框架搭建

    微服务是现在比较流行的技术,对于程序猿而言,了解并搭建一个基本的微服务框架是很有必要滴. 微服务包含的内容非常多,一般小伙伴们可以根据自己的需求不断添加各种组件.框架. 一般情况下,基本的微服务框架包 ...

  6. java架构之路-(微服务专题)初步认识微服务与nacos初步搭建

    历史演变: 以前我们都是一个war包,包含了很多很多的代码,反正我开始工作的时候做的就是这样的项目,一个金融系统,代码具体多少行记不清楚了,内部功能超多,但是实际能用到的不多,代码冗余超大,每次部署大 ...

  7. 十一、Docker搭建部署SpringCloud微服务项目Demo

    环境介绍 技术选型:SpringCloud&SpringCloud Alibaba&Docker 微服务模块划分: 员工模块:ems-employees 部门模块:ems-depart ...

  8. SpringCloudAlibaba 微服务讲解(二)微服务环境搭建

    微服务环境搭建 我们这次是使用的电商项目的商品.订单.用户为案例进行讲解 2.1 案例准备 2.1.1 技术选型 maven :3.3.9 数据库:mysql 持久层:SpringData JPA S ...

  9. (3)go-micro微服务项目搭建

    目录 一 微服务项目介绍 二 go-micro安装 1.拉取micro镜像 2.生成项目目录 三 项目搭建 使用DDD模式开发项目: 四 最后 一 微服务项目介绍 账户功能是每一个系统都绕不开的一部分 ...

  10. springCloud 微服务框架搭建入门(很简单的一个案例不喜勿扰)

    Spring cloud 实现服务注册及发现 服务注册与发现对于微服务系统来说非常重要.有了服务发现与注册,你就不需要整天改服务调用的配置文件了,你只需要使用服务的标识符,就可以访问到服务. clou ...

随机推荐

  1. 论文解读(CDTrans)《CDTrans: Cross-domain Transformer for Unsupervised Domain Adaptation》

    论文信息 论文标题:CDTrans: Cross-domain Transformer for Unsupervised Domain Adaptation论文作者:Tongkun Xu, Weihu ...

  2. 24V转5V降压芯片,24V转3.3V的稳压芯片,中文规格书

    一般说明PW2312 是一个高频,同步,整流,降压,开关模式转换器内部功率 MOSFET.它提供了一个非常紧凑的解决方案,以实现 1.5A 的峰值输出电流在广泛的输入电源范围内,具有优良的负载和线路调 ...

  3. bug处理记录:java.util.UnknownFormatConversionException: Conversion = 'Y'

    1. 报错: java.util.UnknownFormatConversionException: Conversion = 'Y' at java.util.Formatter$FormatSpe ...

  4. Rust学习之旅(读书笔记):枚举 (Enum)

    Rust学习之旅(读书笔记):枚举 (Enum) C 语言的枚举类型很弱,不如后来的语言,也不如之前的语言.在 C 语言里面枚举量就是一个名字,更方便的定义常量.今天读了<The Rust Pr ...

  5. ORM数据库查询优化only与defer(select_related与prefetch_related)

    目录 一:数据库查询优化 1.ORM语句特点 2.only 3.defer 4.only与defer区别 5.select_related与prefetch_related 6.select_rela ...

  6. AIR32F103(七) AIR32F103CBT6/CCT6启用96K内存

    目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...

  7. BST查找结构与折半查找方法的实现与实验比较

    简介 作业:查找结构与排序方法 作业题目: BST 查找结构与折半查找方法的实现与实验比较 要求编写程序实现 BST 存储结构的建立(插入).删除.查找和排序算法: 实现折半查找算法:比较 BST 查 ...

  8. dp 优化

    dp 优化 \(\text{By DaiRuiChen007}\) I. [ARC085D] - NRE \(\text{Link}\) 思路分析 将最终的第 \(i\) 对 \(a_i\) 和 \( ...

  9. Gvim基础操作(正则表达式)-02

    Gvim正则表达式 正则表达式在linux中使用非常广泛.主要是进行一些替换,在编写脚本的时候都会使用到.gvim.perl.sed.tcl中都会使用到. Gvim正则表达式的使用 搜索命令 /正则表 ...

  10. 史上最简单 OpenCV for C++ 在 Windows 和 Ubuntu 上编译安装使用教程

    准备工作 原材料 Ubuntu 系统(非必须,Windows 也可以,主要是 Ubuntu 适合编译) OpenCV 3.4.1 压缩包 OpenCV contrib 3.4.1 压缩包 MinGW( ...