微服务配置文件可视化集中管理 - 第二章
目录
- 微服务配置文件可视化集中管理 - 第二章
- 前言
- 一、JsonConfigurationFileParser源码更改.
- 二、应用站点热更新实现步骤.
- 1.应用站点创建api接口用于接收配置中心配置更改的通知.
- 2.调用ConfigurationRoot里的Reload()函数.
- 3.测试
- 3.1.我们先启动,配置中心站点:http://localhost:41004
- 3.2.在启动应用站点:http://localhost:41000 首次启动,应用站点从配置中心拉取配置信息. 拉取的配置如下:
- 3.3.配置中心,配置更改,通知应用站点.
- 总结
前言
上期回顾:在微服务配置文件可视化集中管理 - 第一章中我们已经实现了在.net core项目中启动的时候,从远程配置中心拉取配置信息,并且自定义实现了IConfigurationProvider提供器,达到了完美兼容.net core应用使用IConfiguration来取配置信息的目的.
本期目标:
- 若配置中心有信息更改,如何通知到所有的应用站点,进行热更新.
- 若配置中心挂了,怎么进行容错,不能因为配置中心宕机,而造成所有的应用站点不能正常工作.
一、JsonConfigurationFileParser源码更改.
在第一章中重写Load()函数时,方法里用到了这样一句代码,JsonConfigurationFileParser.Parse(response);这个函数的作用是让我们将从配置中心拉取回来的Json字符串装换为,key:value的格式(并且支持层级格式)
即如Json:
{
"database": "Server=192.168.10.146;Database=DAS;User ID=xxx;Password=xxx;Pooling=true;Max Pool Size=500;Connection Lifetime=20;",
"baseApi": {
"dk": "193.168.10.146"
}
}
我们要通过无缝适配获取方式:
var baseApi = _configuration[“baseApi:dk”];
就需要JsonConfigurationFileParser.Parse(response);这句代码,
它的作用,是将Json串,转化为ConfigurationProvider里的Data,它的类型时一个字典IDictionary<string, string>.这样我们在用的时候,就可以方便的取到值了.
JsonConfigurationFileParser更改后的源码如下:(直接复制到你的项目,使用就行):
public class JsonConfigurationFileParser
{
private readonly IDictionary<string, string> _data = (IDictionary<string, string>) new SortedDictionary<string, string>((IComparer<string>) StringComparer.OrdinalIgnoreCase);
private readonly Stack<string> _context = new Stack<string>();
private string _currentPath;
private string jsonText;
private JsonConfigurationFileParser(string jsonText)
{
this.jsonText = jsonText;
}
public static IDictionary<string, string> Parse(string jsonText) => new JsonConfigurationFileParser(jsonText).ParseStream();
private IDictionary<string, string> ParseStream()
{
this._data.Clear();
this.VisitJObject(JObject.Parse(jsonText));
return this._data;
}
private void VisitJObject(JObject jObject)
{
foreach (JProperty property in jObject.Properties())
{
this.EnterContext(property.Name);
this.VisitProperty(property);
this.ExitContext();
}
}
private void VisitProperty(JProperty property) => this.VisitToken(property.Value);
private void VisitToken(JToken token)
{
switch (token.Type)
{
case JTokenType.Object:
this.VisitJObject(token.Value<JObject>());
break;
case JTokenType.Array:
this.VisitArray(token.Value<JArray>());
break;
case JTokenType.Integer:
case JTokenType.Float:
case JTokenType.String:
case JTokenType.Boolean:
case JTokenType.Null:
case JTokenType.Raw:
case JTokenType.Bytes:
this.VisitPrimitive(token.Value<JValue>());
break;
default:
throw new FormatException("JToken is error");
}
}
private void VisitArray(JArray array)
{
for (int index = 0; index < array.Count; ++index)
{
this.EnterContext(index.ToString());
this.VisitToken(array[index]);
this.ExitContext();
}
}
private void VisitPrimitive(JValue data)
{
string currentPath = this._currentPath;
if (this._data.ContainsKey(currentPath))
throw new FormatException("JValue is Error");
this._data[currentPath] = data.ToString((IFormatProvider) CultureInfo.InvariantCulture);
}
private void EnterContext(string context)
{
this._context.Push(context);
this._currentPath = ConfigurationPath.Combine(this._context.Reverse<string>());
}
private void ExitContext()
{
this._context.Pop();
this._currentPath = ConfigurationPath.Combine(this._context.Reverse<string>());
}
}
上面的代码,更改处其实是如下的地方:
//更改源码前
private IDictionary<string, string> ParseStream(Stream input)
{
this._data.Clear();
this._reader = new JsonTextReader((TextReader) new StreamReader(input));
this._reader.DateParseHandling = DateParseHandling.None;
this.VisitJObject(JObject.Load((JsonReader) this._reader));
return this._data;
}
//更改源码后
private IDictionary<string, string> ParseStream()
{
this._data.Clear();
this.VisitJObject(JObject.Parse(jsonText));
return this._data;
}
这就是第一章中说的,需要将远程获取的jsonText,通过这个类的转化,就可以写入字典Data里了(稍微更改一下源码),以此实现无缝衔接原来的IConfiguration获取配置的方式.
二、应用站点热更新实现步骤.
注意:
配置中心站点:http://localhost:41004
拉取最新配置接口地址:http://localhost:41004/api/Configs
请求参数:
key:配置标识(通过这个标识,能拉取到各自应用的配置)
dev:环境标签(通过这个标识,拉取指定的环境配置,当然也可以不传,这样取什么环境的配置,完成交给配置中心来管理,也是可以的)
请求方式:GET
应用站点:http://localhost:41000
应用站点用于接收通知的接口地址:http://localhost:41000/api/Test/Notify
请求参数:无
请求方式:GET
1.应用站点创建api接口用于接收配置中心配置更改的通知.
应用站点http://localhost:41000接收配置更改通知的代码如下(示例):
/// <summary>
/// 测试接收配置文件更改通知
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : Controller
{
/// <summary>
/// 构造函数注入
/// </summary>
IConfiguration _configuration;
public TestController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public bool Notify()
{
var configurationRoot = (ConfigurationRoot) _configuration;
configurationRoot.Reload();
return true;
}
}
这里接收配置中心,通知的接口路由为:/api/Test/Notify
2.调用ConfigurationRoot里的Reload()函数.
可以看到,这句代码configurationRoot.Reload():
var configurationRoot = (ConfigurationRoot) _configuration;
configurationRoot.Reload();
我们调用了Reload()函数,就能达到热更新.非常简单.官方已经给我们提供了这个接口IConfigurationRoot,它里面就有个Reload()函数,专门为我们做热更新的,它是继承了IConfiguration,具体继承关系,如下图所示:
3.测试
3.1.我们先启动,配置中心站点:http://localhost:41004
3.2.在启动应用站点:http://localhost:41000 首次启动,应用站点从配置中心拉取配置信息. 拉取的配置如下:
{
"database": "Server=192.168.10.146;Database=DAS;User ID=xxx;Password=xxx;Pooling=true;Max Pool Size=500;Connection Lifetime=20;",
"baseApi": {
"dk": "193.168.10.146"
}
}
我们请求应用站点,用于测试的action,看首次获取的配置.
/// <summary>
/// 测试配置文件获取
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : Controller
{
/// <summary>
/// 构造函数注入
/// </summary>
IConfiguration _configuration;
public TestController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public List<KeyValuePair<string,string>> Get()
{
var list = new List<KeyValuePair<string, string>>();
var database = _configuration["database"];
var baseApi = _configuration["baseApi:dk"];
list.Add(new KeyValuePair<string, string>("database",database));
list.Add(new KeyValuePair<string, string>("baseApi",baseApi));
return list;
}
}
请求:http://localhost:41000/api/test/get
这时候,我们成功获取到了配置文件.
3.3.配置中心,配置更改,通知应用站点.
配置中心,更改后的配置为如下所示:
{
"database": "Server=.",
"baseApi": {
"dk": "我更改了"
}
}
调用应用站点通知接口:
http://localhost:41000/api/test/Notify
/// <summary>
///
/// </summary>
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : Controller
{
/// <summary>
/// 构造函数注入
/// </summary>
IConfiguration _configuration;
public TestController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public bool Notify()
{
var configurationRoot = (ConfigurationRoot) _configuration;
configurationRoot.Reload();
return true;
}
}
通知以后,在请求http://localhost:41000/api/test/get,看配置信息是否已经热更新?
打断点后,结果如下截图所示:
好了,已经完美的实现了热更新.
总结
- 当前解决了热更新的问题.但是配置中心挂了,怎么进行容错,不能因为配置中心宕机,而造成所有的应用站点不能正常工作.**微服务配置文件可视化集中管理 - 第三章(完结篇)**中详细解答.