自动驾驶初创公司Momenta获得4600万美元B轮投资,蔚来资本领投
06-18
1 什么是分布式配置中心,其实就是将一些配置信息从自己的系统中分离出来,并且这些信息可以被应用程序实时获取。这里我们以springboot为例。
我们都知道springboot启动时会加载资源目录下的application.properties或者application.yml。这时我们把springboot启动时需要加载的配置文件和项目放在一起,统一管理。
这就是分布式配置中心的核心思想。 1.1 分布式配置中心由哪些部分组成? 1.1.1.有一个可以操作配置的界面。
1.1.2.数据可以持久化(防止丢失,服务离线时配置仍然存在)。 1.1.3.有一个客户端和一个服务器。
,客户端主动拉取数据或者服务端主动推送数据。并刷新本机的配置。
(核心)1.1.4、管理界面、权限系统等一些操作日志。 2、市面上主流的配置中心2.1阿里巴巴的nacosNacos致力于帮助您发现、配置和管理微服务。
Nacos 提供了简单易用的功能集,帮助您快速实现动态服务发现、服务配置、服务元数据和流量管理。 Nacos 帮助您更敏捷、更轻松地构建、交付和管理微服务平台。
Nacos是构建以“服务”为中心的现代应用架构(如微服务范式、云原生范式)的服务基础设施。具体使用请参见官网2.2。
nacos的原理是通过长链接来监控服务配置是否发生变化。发送给客户端的架构示意图如下。
这是推送模式,但它是基于长链接image.png2.3。携程的ApolloApollo是携程框架部开发并开源的生产级配置中心产品。
它可以集中管理不同环境、不同集群的配置中的应用,配置修改后可以实时推送到应用端,并具有标准化的权限、流程治理等特性,适合微服务配置管理场景。具体使用方法请查看官网。
携程的架构示意图和Nacos是一样的。也是长链接轮询和服务器推送模式。
2.3 spirgcloud configspringCloudConfig,支持将配置服务放置在配置服务的内存中(即本地),也支持放置在远程Git/svn仓库中。当image.png服务启动时,config服务会从远程git拉取配置文件并存储到本地git文件库中。
当远程git不可用时,将从本地git文件库中拉取配置信息。具体使用方法请以官网为准。
2.4 百度disconf Disconf是百度开源的一款基于Zookeeper的分布式配置管理软件。目前,很多公司都在使用,包括滴滴、百度、网易、顺丰速运等公司。
通过简单的界面操作就可以非常方便的动态修改配置属性。使用Disconf后发现的一大好处是不需要应用大量配置,并且配置可以自动加载并实时生效。
基本原理图:当然,具体的肯定比这个复杂,这只是主要流程。 image.png3 如何实现自己的分布式配置中心 3.1 动态修改本地@Value注解配置 3.2 如何同时修改不同bean中的同一个值。
4、关于如何动态修改@Value注解的配置的具体思路,我们需要知道springboot是如何加载application.ym或application.properties文件的。我这里使用springboot2.1.1的代码作为演示。
首先打开image.png,找到spring.factors的配置文件image.png。我们看到上面三个是配置文件的加载器。
这也说明了为什么properties的优先级高于yaml。他按照从上到下的顺序排列。
但实际的配置文件仍然执行如下。我们点击查看实现类ConfigFileApplicationListene的代码语言: javascript copy @Overridepublic void postProcessEnvironment(ConfigurableEnvironmentenvironment, SpringApplication application) { //如何加载资源 addPropertySources(environment, application.getResourceLoader()) ;}protected void addPropertySources(ConfigurableEnvironment)环境,ResourceLoader资源加载器){RandomValuePropertySource.addToEnvironment(环境); // 将资源加载到环境变量中 new Loader(environment, resourceLoader).load(); }// 然后使用propertySource解析器进行解析 Loader(ConfigurableEnvironmentenvironment, ResourceLoaderresourceLoader) { this.environment =environment; } this.placeholdersResolver = new PropertySourcesPlaceholdersResolver( this.environment); this.resourceLoader = (resourceLoader!= null) ?资源加载器:新的默认资源加载器(); this.propertySourceLoaders = SpringFactoriesLoader.loadFactories( PropertySourceLoader.class, getClass().getClassLoader());} 那么我们就知道了,就是如果我们能够环境PostProcessor,我们就可以通过重写里面的方法来动态加载配置文件。
现在我们开始代码实现。 4.1 代码实现 这种情况下,我们可以实现EnvironmentPostProcessor类,通过接口动态加载配置文件。
那么下面是具体的代码实现代码语言:txt copy @AutowiredConfigurableEnvironmentconfigurableEnvironment; @AutowiredEnvironment环境; @Testpublic void test() { String name =environment.getProperty("name"); System.out.printf("动态加载前" +name); Map
第二个问题是如何动态刷新@value注解。那么对于这个用途,我们需要ConfigurablePropertyResolver类来解析key,找到@value对应的bean后,通过反射刷新具体代码 4.2 代码实现代码语言:txt copy public static voidfreshBean(Object bean, ConfigurablePropertyResolver propertyResolver) { // 定义 EL 表达式解释器 SpelExpressionParser spelExpressionParser = new SpelExpressionParser(); TemplateParserContext templateParserContext= new TemplateParserContext();字符串 keyResolver, valueResolver = null;对象解析器值; // 获取真实对象属性 Field[] declaredFields = bean.getClass().getDeclaredFields (); boolean cglib = Arrays.stream(declaredFields).anyMatch(x -> x.getName().contains("CGLIB")); // 如果是cglib代理,则找到其父类 if(cglib){ declaredFields = bean .getClass().getSuperclass().getDeclaredFields(); } // 遍历Bean实例的所有属性 for (Field field : declaredFields) { // 判断field是否包含@Value注解 if (field.isAnnotationPresent(Value.class)) { // 读取Value注解占位符 keyResolver = field.getAnnotation(Value.clas).value(); try { // 读取属性值 valueResolver = propertyResolver.resolveRequiredPlaceholders(keyResolver); // EL表达式解析 // 兼容形如:@Value("#{'${codest. Five.url}'.split(',')}") 含有EL表达式的情况 Expression expression = spelExpressionParser.parseExpression (valueResolver, templateParserContext); if(field.getType() == Boolean.class){ parserValue =Boolean.valueOf(expression.getValue().toString()); } else if(field.getType() == Integer.class){ parserValue =Integer.valueOf(expression.getValue().toString()); } else if(field.getType() == Long.class){ parserValue =Long.valueOf(expression.getValue().toString()); }else { parserValue = expression.getValue(field.getType()); }} catch (IllegalArgumentException e) { 继续; } // 判断配置项是否存在 if (Objects.nonNull(valueResolver)) { field.setAccessible(true);尝试 { field.set(bean, parserValue);继续; } catch ( IllegalAccessException e) { e.printStackTrace();我们正在编写一个单元测试 Test 4.2.1 单元测试 image.pngimage.png 代码语言:txt copy @AutowiredConfigurableEnvironmentconfigurableEnvironment; @AutowiredConfigurablePropertyResolver 可配置PropertyResolver; @AutowiredPerson 人; @Testpublic void test() { System.out.printf("动态加载前" +person.getName()); Map
下一期我们将解决当多个bean具有相同@value值时如何同时刷新特定文档的问题。我们先挖金子。
请关注掘金队。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-17
06-21
06-21
06-18
06-18
06-18
06-18
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用