.NetCore下构建自己的服务配置中心-手动造轮子
本人主要利用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配置然后刷新客户端看结果:


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

.NetCore下构建自己的服务配置中心-手动造轮子的更多相关文章
- 【微服务】之三:从零开始,轻松搞定SpringCloud微服务-配置中心
		
在整个微服务体系中,除了注册中心具有非常重要的意义之外,还有一个注册中心.注册中心作为管理在整个项目群的配置文件及动态参数的重要载体服务.Spring Cloud体系的子项目中,Spring Clou ...
 - SpringCloud04 服务配置中心、消息总线、远程配置动态刷新
		
1 环境说明 JDK:1.8 MAVENT:3.5 SpringBoot:2.0.5.RELEASE SpringCloud:Finchley.SR1 2 创建服务注册中心(Eureka服务端) 说明 ...
 - Spring Cloud Alibaba 整合 Nacos 实现服务配置中心
		
在之前的文章 <Nacos 本地单机版部署步骤和使用> 中,大家应该了解了 Nacos 是什么?其中 Nacos 提供了动态配置服务功能 一.Nacos 动态配置服务是什么? 官方是这么说 ...
 - MongoDB4.0在windows10下的安装与服务配置
		
本地安装及网页测试 在官网下载最新的安装文件 下载地址 : https://www.mongodb.com/download-center#community 可以在MongoDB官网选择Commun ...
 - .NetCore下构建自己的文件服务管理(UosoOSS)
		
Web开发系统文件默认存储在wwwroot目录下面,现在越来越多的系统服务化了,UI也更加多元化,当然文件可以用第三方的文件服务,但是这里准备文件分离出来构建自己的文件服务配合数据库表来实现(Uoso ...
 - SpringCloud服务配置中心
		
SpringCloud Config简介 Spring Cloud Config 是 Spring Cloud 团队创建的一个全新项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持 ...
 - 微服务配置中心实战:Spring + MyBatis + Druid + Nacos
		
在结合场景谈服务发现和配置中我们讲述了 Nacos 配置中心的三个典型的应用场景,包括如何在 Spring Boot 中使用 Nacos 配置中心将数据库连接信息管控起来,而在“原生”的 Spring ...
 - Spring Cloud Alibaba系列(二)nacos作为服务配置中心
		
Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持.使用 Spring Cloud Alibaba Nacos Config,您可 ...
 - SpringCloud+Nacos实现服务配置中心(Hoxton版本)
		
关于 Nacos Spring Cloud 的详细文档请参看:Nacos Config和Nacos Discovery. 通过 Nacos Server 和 spring-cloud-starter- ...
 
随机推荐
- springboot项目中集成ip2region遇到的问题及终极解决办法
			
1.问题回顾 按照ip2region项目的官方集成到springboot项目后,运行测试一切都ok,没有任何问题.但是当项目打成可执行的jar包后再运行,却显示找不到ip2region.db,无法找到 ...
 - RestTemplate进行访问分页PageInfo
			
废话少说,给你们看代码: //provide的controller @ResponseBody @RequestMapping(value = "details",method = ...
 - 南邮CTF-MISC-Remove Boyfriend
			
Remove Boyfriend 打开wireshark,找到关键字部分Remove Boyfriend 在第五行 在此行右击 点击追踪流 选择TCP流,可以分析出流量的传输过程 通过上面的执行列表 ...
 - Mysql配置文件 基本设置
			
[mysqld] #MySQL启动用户 user = mysql #设置mysql的安装目录 basedir=/usr/local/mysql #mysql.sock存放目录 socket=/var/ ...
 - ABP VNext框架基础知识介绍(2)--微服务的网关
			
ABP VNext框架如果不考虑在微服务上的应用,也就是开发单体应用解决方案,虽然也是模块化开发,但其集成使用的难度会降低一个层级,不过ABP VNext和ABP框架一样,基础内容都会设计很多内容,如 ...
 - [OpenGL ES 02]OpenGL ES渲染管线与着色器
			
[OpenGL ES 02]OpenGL ES渲染管线与着色器 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循"署名-非商业用途-保持一致"创 ...
 - Python语法之基本数据类型
			
一.数据类型之字符串str 作用:主要用于记录描述性性质的数据,如姓名.地址.邮箱: 定义: 方式1 # 单引号 name = 'jason' 方式2 # 双引号 name = "jason ...
 - .net 6 (.net core) 发布到linux docker中
			
第一步:VMware 安装 虚拟机Linux系统,本文以 CentOS 为例 .
 - 动手做个 AI 机器人,帮我回消息!
			
大家好,我是鱼皮,自从做了知识分享,我的微信就没消停过,平均每天会收到几百个消息,大部分都是学编程的朋友向我咨询编程问题. 但毕竟我只有一个人,没法所有消息都一个个回复,所以也是很愧疚和无力吧:另外我 ...
 - JAVAWEB项目报"xxx响应头缺失“漏洞处理方案
			
新增一个拦截器,在拦截器doFilter()方法增加以下代码 public void doFilter(ServletRequest request, ServletResponse response ...