我的架构之路 — 配置中心(三)— 动态更新配置

简介:

包含两方面的含义:
一、变化的配置能够下发到客户端.
二、客户端能够方便地处理这些变化的配置。下面会讲普通监听器回调方式和spring 注解到field的方式。

配置下发

1)客户端间隔20秒(可配)去数据库拉取配置,sql传递的参数有配置名称、环境、上一次最大更新时间
2)取到配置后,合并更新本地备份。
3)通过监听器的方式通知配置变化。


#监听器接口
public interface ConfigUpdateListener {
   void update(Properties properties);
}

#启动时添加监听器
 public void addConfigUpdateListener(ConfigUpdateListener configUpdateListener) {
        configUpdateListeners.add(configUpdateListener);
    }


#配置变化,调用监听器进行通知
  for (ConfigUpdateListener configUpdateListener : configUpdateListeners) {
                configUpdateListener.update(changedProperties);
            }

spring 注解方式绑定成员变量

通过@ConfigValue注解来实现变量绑定,当配置变化的时候会同时更新这个变量。这种方式可以用于一起开关切换、降级处理的场景。

@ConfigValue("baseUrl")
private String baseUrl;

实现原理:
1)从配置中心获取配置。
2)通过BeanPostProcessor 遍历每个spring bean,找出所有包含@ConfigValue注解的field,然后设置值为配置中心的属性值,同时把记录field到Map对象,以后更新配置时就不用想办法遍历了。这里有一个严格处理原则,如果配置中心找不到相应key或值赋值时候报异常,终止程序,保证安全性。
其实代码对非spring的、static 成员变量也支持,只是需要程序启动时候指定包含这些static变量的类名列表。

public class PropertyPlaceholderConfigurer extends
        org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
        implements BeanPostProcessor
{
    private Map<String,List<BeanField>> configMap= new ConcurrentHashMap<String,List<BeanField>>();
     
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        ConfigInjectSupport.inject(mergedProperties,bean.getClass(),bean,configMap);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        return bean;
    }
public static void inject(Properties properties, Class clazz, Object bean, Map<String,List<BeanField>> configMap){
        Field[] fields = clazz.getDeclaredFields();
        if (null != fields) {
            for (Field f : fields) {
                // 如果 bean ==null(非spring),则必须是静态方法
                if(bean==null &&  !Modifier.isStatic(f.getModifiers())) continue;
                ConfigValue configValue = f.getAnnotation(ConfigValue.class);
                if (configValue != null) {
                    String key = configValue.value();
                    f.setAccessible(true);
                    Object value = properties.get(key);
                    if (value != null) {
                        try {
                            f.set(bean, converter.convertIfNecessary(value, f.getType(), f));
                        } catch (IllegalAccessException e) {
                            throw  new RuntimeException(e);
                        }
                    }else{
                        RuntimeException e= new RuntimeException("can not find config. key="+key+", class="+clazz+", field="+f.getName());
                        e.printStackTrace();
                        throw e;
                    }
                    List<BeanField> list = configMap.get(key);
                    if (list == null) {
                        list = new ArrayList<BeanField>();
                        configMap.put(key, list);
                    }
                    BeanField beanField=new BeanField();
                    beanField.setBean(bean);
                    beanField.setField(f);
                    list.add(beanField);
                }

            }

        }
        clazz = clazz.getSuperclass();
    }

3)加入监听器,接收变化的配置,更新field值

public static void addConfigUpdateListener(final Map<String,List<BeanField>> configMap) {
        DefaultConfigClient.addConfigUpdateListener(new ConfigUpdateListener() {
            @Override
            public void update(Properties properties) {
                for (Map.Entry<Object, Object> e : properties.entrySet()) {
                    List<BeanField> beanFields = configMap.get(e.getKey().toString());
                    if (beanFields != null) {
                        Object value = properties.get(e.getKey());
                        for (BeanField beanField : beanFields) {
                            try {
                                ConfigValue configValue = beanField.getField().getAnnotation(ConfigValue.class);
                                if(configValue.updatable()) {
                                    ConfigInjectSupport.setFieldValue(beanField, value);
                                }
                            } catch (IllegalAccessException ex) {
                                ex.printStackTrace();
                            }
                        }
                    }

                }
            }
        });
    }

 public static void setFieldValue(BeanField beanField,Object value) throws IllegalAccessException {
        Field f=beanField.getField();
        f.set(beanField.getBean(), ConvertUtils.convert(value,f.getType()));
    }
目录
相关文章
|
网络协议 Linux
Linux DNS服务详解——DNS主从架构配置
Linux DNS服务详解——DNS主从架构配置
826 4
|
4月前
|
人工智能 运维 安全
配置驱动的动态 Agent 架构网络:实现高效编排、动态更新与智能治理
本文所阐述的配置驱动智能 Agent 架构,其核心价值在于为 Agent 开发领域提供了一套通用的、可落地的标准化范式。
824 65
|
4月前
|
人工智能 安全 数据可视化
配置驱动的动态Agent架构网络:实现高效编排、动态更新与智能治理
本文系统性地提出并阐述了一种配置驱动的独立运行时Agent架构,旨在解决当前低代码/平台化Agent方案在企业级落地时面临困难,为Agent开发领域提供了一套通用的、可落地的标准化范式。
427 18
配置驱动的动态Agent架构网络:实现高效编排、动态更新与智能治理
|
10月前
|
网络协议 Java 应用服务中间件
框架源码私享笔记(01)Tomcat核心架构功能 | 配置详解
本文首先分享了《活出意义来》一书序言中的感悟,强调成功如同幸福,不是刻意追求就能得到,而是全心投入时的副产品。接着探讨了Tomcat的核心功能与架构解析,包括网络连接器(Connector)和Servlet容器(Container),并介绍了其处理HTTP请求的工作流程。文章还详细解释了Tomcat的server.xml配置文件,涵盖了从顶级容器Server到子组件Connector、Engine、Host、Context等的配置参数及作用,帮助读者理解Tomcat的内部机制和配置方法。
|
11月前
|
存储 人工智能 并行计算
2025年阿里云弹性裸金属服务器架构解析与资源配置方案
🚀 核心特性与技术创新:提供100%物理机性能输出,支持NVIDIA A100/V100 GPU直通,无虚拟化层损耗。网络与存储优化,400万PPS吞吐量,ESSD云盘IOPS达100万,RDMA延迟<5μs。全球部署覆盖华北、华东、华南及海外节点,支持跨地域负载均衡。典型应用场景包括AI训练、科学计算等,支持分布式训练和并行计算框架。弹性裸金属服务器+OSS存储+高速网络综合部署,满足高性能计算需求。
|
存储 SQL 消息中间件
Hadoop-26 ZooKeeper集群 3台云服务器 基础概念简介与环境的配置使用 架构组成 分布式协调框架 Leader Follower Observer
Hadoop-26 ZooKeeper集群 3台云服务器 基础概念简介与环境的配置使用 架构组成 分布式协调框架 Leader Follower Observer
222 0
|
NoSQL Redis
Redis 主从复制架构配置及原理
Redis 主从复制架构配置及原理
226 5
|
监控 安全 API
Android项目架构设计问题之保证线上用户不会进入到本地配置页面如何解决
Android项目架构设计问题之保证线上用户不会进入到本地配置页面如何解决
121 0
|
JSON Android开发 数据格式
Android项目架构设计问题之在远端动态配置中添加相应配置如何解决
Android项目架构设计问题之在远端动态配置中添加相应配置如何解决
106 0
|
监控 算法 Java
高并发架构设计三大利器:缓存、限流和降级问题之配置Sentinel的流量控制规则问题如何解决
高并发架构设计三大利器:缓存、限流和降级问题之配置Sentinel的流量控制规则问题如何解决
314 0