本人主要利用IdentityServer4以及SignalR来实现,IdentityServer4作为认证,SignalR来交互配置,这里一些代码可能就是部分提出来,主要介绍实现原理及方法

实现配置中心核心的两个点我们要放在

1、配置文件如何传送

2、配置文件如何动态的更新

配置文件的传送结合SignalR来实现

思考:什么样的客户端可以来获取配置?

这里客户端我们配置了

这里我直接结合Identityserver4,配置客户端id,客户端密钥,配置中心地址、在配置一个IdentityServer4授权地址, 根据这些配置设计下配置中心的 数据库表,这里直接略

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConfigCenter": {
"AuthUrl": "http://192.168.0.42:7000",
"ClientId": "configclient",
"ClientSecret": "configclient",
"ServerUrl": "http://localhost:6002"
}, "AllowedHosts": "*"
}

然后只有手鲁SignalR代码来出来连接消息交互了,不用在去早socket的轮子了,此处了略去,为了准备给自己的服务使用,只有把这个写成SDK

这里我们需要一个服务类:ClientServices 这个类用来出来 SignalR相关处理 以及配置Json数据的格式话,需要json配置转换成 .NetCore配置 ,开过配置中的 Data对象的都知道 这个Data中的格式是 {Logging:LogLevel,"1231"}这种键值对,怎么来把Json数据处理成为这个数据呢?后面介绍简便方法

这里对象类需要了解清楚 IConfigruationBuilder、IConfigurationProvider、IConfigurationSource ,这块不做介绍,而我们要做的就是结合这个来处理我们的配置

建立了三个项目来处理

ConfigCenter:配置服务端API接口,提供给UI 配置管理相关接口

ConfigCenterClient :客户端配置SDK,提供给服务端连接配置中心提供配置库

ConfigCenterTest::客户端服务测试API

配置文件动态更新

首先来开下ConfigurationProvider的源码

  //
// 摘要:
// Base helper class for implementing an Microsoft.Extensions.Configuration.IConfigurationProvider
public abstract class ConfigurationProvider : IConfigurationProvider
{
//
// 摘要:
// Initializes a new Microsoft.Extensions.Configuration.IConfigurationProvider
protected ConfigurationProvider(); //
// 摘要:
// The configuration key value pairs for this provider.
protected IDictionary<string, string> Data { get; set; } //
// 摘要:
// Returns the list of keys that this provider has.
//
// 参数:
// earlierKeys:
// The earlier keys that other providers contain.
//
// parentPath:
// The path for the parent IConfiguration.
//
// 返回结果:
// The list of keys for this provider.
public virtual IEnumerable<string> GetChildKeys(IEnumerable<string> earlierKeys, string parentPath);
//
// 摘要:
// Returns a Microsoft.Extensions.Primitives.IChangeToken that can be used to listen
// when this provider is reloaded.
//
// 返回结果:
// The Microsoft.Extensions.Primitives.IChangeToken.
public IChangeToken GetReloadToken();
//
// 摘要:
// Loads (or reloads) the data for this provider.
public virtual void Load();
//
// 摘要:
// Sets a value for a given key.
//
// 参数:
// key:
// The configuration key to set.
//
// value:
// The value to set.
public virtual void Set(string key, string value);
//
// 摘要:
// Generates a string representing this provider name and relevant details.
//
// 返回结果:
// The configuration name.
public override string ToString();
//
// 摘要:
// Attempts to find a value with the given key, returns true if one is found, false
// otherwise.
//
// 参数:
// key:
// The key to lookup.
//
// value:
// The value found at key if one is found.
//
// 返回结果:
// True if key has a value, false otherwise.
public virtual bool TryGet(string key, out string value);
//
// 摘要:
// Triggers the reload change token and creates a new one.
protected void OnReload();

注意可以看到 Load方法都是虚方法,就是提供给我扩展的,接下来就是关键的一步在这个上面处理

构建自己的服务提供类来重写该方法,然后注入一个事件,提供给外部改变更新的能力

public class LYMConfigProvider : ConfigurationProvider
{
private ClientServices Client { get; } public LYMConfigProvider(ClientServices clientServices)
{
Client = clientServices;
} private void LoadData(IDictionary<string, string> values)
{
foreach (var item in values)
{

               if (item.Key.EndsWith("0"))
{
var likekey= item.Key.Substring(0, item.Key.Length - 1);
foreach (var da in Data)
{
if (da.Key.StartsWith(likekey))
{
Data.Remove(da.Key);
}
}
}
if (Data.ContainsKey(item.Key))
Data.Remove(item.Key);
Data.Add(item.Key, item.Value);
 } } public override void Load() { Client.Changed += (arg) => { LoadData(arg.customdata); base.OnReload(); }; var lst = Client.InitClientConfig(); LoadData(lst); } }

通过注册改变事件,外部就可以通过该事件来实现配置的更新了,值得注意的Load的时候我们需要初始化下配置,毕竟SignalR连接回复初始配置会出现延迟,导致Startup中IConfiguraion初始配置为空

接下来说一个关键的问题,就是得到的Json怎么序列化出来到Data中,而Data的类型又是:

//
// 摘要:
// The configuration key value pairs for this provider.
protected IDictionary<string, string> Data { get; set; }

不怕麻烦的朋友可以自己写递归各种转换,但是那样太麻烦了,只能用绝招了,通过ConfigurationBuilder对象Build出来的配置提供类都有一个Data,这个Data .NetCode已经帮我们出来好了,于是自己去构建了一个ConfigurationBuilder这样来处理看行不行?

  byte[] by = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream(by);
var builder = new ConfigurationBuilder().AddJsonStream(ms).Build();

这里调试监控你可以看到Data是有值的,但是你就是取不到,会出现类型转换错误,就算得到Providers强转自己的类型还是会报错,且Data在ConfigurationProvider中是protect ,所以为了处理这个问题,我们不得不建立另外的自己的类来扩展下,构建自定义的配置资源以及配置提供类

因为这里是JsonStream,所以我们来扩展JsonStream就ok,这里我们提供了一个公共的GetData方法,来获取基类中的Data

 public class CustomJsonConfigrationProvider : JsonStreamConfigurationProvider
{
public CustomJsonConfigrationProvider(JsonStreamConfigurationSource jsonStreamConfigurationSource) : base(jsonStreamConfigurationSource)
{ }
public IDictionary<string, string> GetData()
{
return base.Data;
}
}
public class CustomJsonConfigrationSource: JsonStreamConfigurationSource
{
public override IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new CustomJsonConfigrationProvider(this);
}
}

所以如何把Json装换成.netcore中的配置,我们只需要如下代码即可:

    public IDictionary<string, string> BuildDictionary(string json)
{
byte[] by = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream(by);
var source = new CustomJsonConfigrationSource();
source.Stream = ms;
var builder = new ConfigurationBuilder().Add(source).Build();
var data = builder.Providers.First() as CustomJsonConfigrationProvider;
return data.GetData();
}

接下来是校验成果的时候了,通过引用客户端SDK,并配置上自己的配置,准备下服务端的初始配置

 public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
} public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigLYMConfiguration() //这里就是我们SDK自己写的配置扩展方法
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}); }

这里服务端准备一段配置:{"data":"this the init configuration data"} 以及测试发送配置接口

下面我们通过服务的配置来修改下在刷新页面:

在环境配置中添加2两个配置

接下来我们用测试客户端启动起来看下,可以看到客户端实例的信息,以及使用的默认配置

并且访问下客户端站点

下面我们服务端启用Development配置然后刷新客户端看结果:

实现了针对通过一个客户端分布式部署统一更新配置,以及获取连接实例,针对指定服务实例更新配置的功能

参考文献:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#custom-configuration-provider

.NetCore下构建自己的服务配置中心-手动造轮子的更多相关文章

  1. 【微服务】之三:从零开始,轻松搞定SpringCloud微服务-配置中心

    在整个微服务体系中,除了注册中心具有非常重要的意义之外,还有一个注册中心.注册中心作为管理在整个项目群的配置文件及动态参数的重要载体服务.Spring Cloud体系的子项目中,Spring Clou ...

  2. SpringCloud04 服务配置中心、消息总线、远程配置动态刷新

    1 环境说明 JDK:1.8 MAVENT:3.5 SpringBoot:2.0.5.RELEASE SpringCloud:Finchley.SR1 2 创建服务注册中心(Eureka服务端) 说明 ...

  3. Spring Cloud Alibaba 整合 Nacos 实现服务配置中心

    在之前的文章 <Nacos 本地单机版部署步骤和使用> 中,大家应该了解了 Nacos 是什么?其中 Nacos 提供了动态配置服务功能 一.Nacos 动态配置服务是什么? 官方是这么说 ...

  4. MongoDB4.0在windows10下的安装与服务配置

    本地安装及网页测试 在官网下载最新的安装文件 下载地址 : https://www.mongodb.com/download-center#community 可以在MongoDB官网选择Commun ...

  5. .NetCore下构建自己的文件服务管理(UosoOSS)

    Web开发系统文件默认存储在wwwroot目录下面,现在越来越多的系统服务化了,UI也更加多元化,当然文件可以用第三方的文件服务,但是这里准备文件分离出来构建自己的文件服务配合数据库表来实现(Uoso ...

  6. SpringCloud服务配置中心

    SpringCloud Config简介 Spring Cloud Config 是 Spring Cloud 团队创建的一个全新项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持 ...

  7. 微服务配置中心实战:Spring + MyBatis + Druid + Nacos

    在结合场景谈服务发现和配置中我们讲述了 Nacos 配置中心的三个典型的应用场景,包括如何在 Spring Boot 中使用 Nacos 配置中心将数据库连接信息管控起来,而在“原生”的 Spring ...

  8. Spring Cloud Alibaba系列(二)nacos作为服务配置中心

    Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持.使用 Spring Cloud Alibaba Nacos Config,您可 ...

  9. SpringCloud+Nacos实现服务配置中心(Hoxton版本)

    关于 Nacos Spring Cloud 的详细文档请参看:Nacos Config和Nacos Discovery. 通过 Nacos Server 和 spring-cloud-starter- ...

随机推荐

  1. Function overloading and return type

    In C++ and Java, functions can not be overloaded if they differ only in the return type. For example ...

  2. ArrayList删除特定元素的方法

    最朴实的方法,使用下标的方式: ArrayList<String> al = new ArrayList<String>(); al.add("a"); a ...

  3. Js判断数组中是否存在某个元素

    Js判断数组中是否存在某个元素 方法一:indexOf(item,start); Item:要查找的值:start:可选的整数参数,缺省则从起始位子开始查找. indexOf();返回元素在数组中的位 ...

  4. linux系统下命令的学习

    本博客是本人工作时做的笔记 ps aux |grep ^profile |grep A190200024 ^ 表示行首匹配 linux查看文件大小: 具体可查看:https://www.cnblogs ...

  5. Java SPI机制,你了解过吗?

    Life moves pretty fast,if you don't stop and look around once in a while,you will miss it 为什么需要SPI? ...

  6. JavaMoney规范(JSR 354)与对应实现解读

    一.概述 1.1 当前现状 当前JDK中用来表达货币的类为java.util.Currency,这个类仅仅能够表示按照**[ISO-4217]**描述的货币类型.它没有与之关联的数值,也不能描述规范外 ...

  7. Nginx状态码和日志

    目录 一.Nginx状态返回码 二.Nginx日志统计 一.Nginx状态返回码 http返回状态码(Status-Code), 以3位数字组成 200 成功 301 永久重定向(redirect) ...

  8. Jmeter——脱离Jenkins后,Ant集成邮件通知

    之前搭建在本地的Jenkins环境,由于重装系统的原因,环境不能用了.在用jmeter做测试的时候,索性用本地ant构建,运行下来也一样平稳. 结合Jenkins搭建环境,可以参考博文:Jenkins ...

  9. CSS选择器类型总结

    CSS选择器类型总结 1.通用选择器 一般用于给所有元素做一些通用性的样式设置,比如清除内边距.外边距等.但是效率比较低,尽量不要使用. * { margin: 0; padding: 0; } 2. ...

  10. SP1798 ASSIST - Assistance Required 题解

    Content 有一个足够长的数列 \(a\),是一个首项为 \(2\),公差为 \(1\) 的等差递增数列.另有一个初始为空的数列 \(b\). 重复进行如下操作: 假设当前数列 \(a\) 第一项 ...