zoukankan      html  css  js  c++  java
  • Dubbo配置完全外部化实践,使用动态配置中心的注意事项

    问题描述

    近期开发项目,将Dubbo的配置全部外部化到动态配置中心。这里配置中心我使用的是Apollo。

    @Configuration
    public class DubboConfig {
      @Bean
      public ConfigCenterConfig configCenterConfig() {
        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
        configCenterConfig.setAddress("apollo.xxxxx.com");
        configCenterConfig.setProtocol("apollo");
        configCenterConfig.setNamespace("dubbo");
        configCenterConfig.setGroup(null);
        return configCenterConfig;
      }
    }
    
    

    这里使用dubbo这个namespace。

    其余配置全部配置在这个里面。

    然后遇到一个大坑:

    这里项目中定义了一个Service,也就是作为Provider提供了版本为provider.auth.version的服务。

    package io.github.slankka.provider;
    
    @Service(version = "${provider.auth.version:1.0}")
    @Slf4j
    public class AuthApiService implements IAuthApi 
    

    项目启动之后,注册到注册中心的版本是1.0。

    在dubbo命名空间中定义了provider.auth.version=20000,但是启动还是1.0

    问题分析

    Apollo启动模式分为两种,一种是在 BeanDefinition阶段就将配置注入Spring容器内的Environment。另一种是在PostBeanFactory的时候启动。
    而Dubbo启动的时候,所有的Service是ServiceBean的实例对应生成的代理类,所有的Reference是ReferenceBean的实例对应生成的代理类。
    因此如果这里使用placeholder要被Spring识别,那么将必须选用第一种启动方式。

    问题解决

    在本地项目的application.properties中配置:

    apollo.bootstrap.enabled = true
    apollo.bootstrap.namespaces = application,dubbo
    

    注意,这里apollo.bootstrap.namespaces 中加入了dubbo,这里有一个疑问:
    之前配置Dubbo的时候不是定义了ConfigCenterConfig的namespace了吗,为什么还要定义一次。

     configCenterConfig.setNamespace("dubbo");
    

    原因是:
    Dubbo的ServiceBean在被Spring工厂构建出来的时候,就需要这个变量。但如果没有配置dubbo到apollo.bootstrap.namespaces,Spring会报错。
    如果接口上写了默认版本,上例是1.0,则Spring不会报错,但是构建出来的对应ServiceBean中的版本将会是1.0,而Dubbo启动之后依然不会修改这个版本。

    新的问题

    为什么Dubbo的namespace中配置了这个变量,而且Dubbo在启动早起阶段就已经拉到了这些变量,但版本仍旧没有发生改变?

    看一下Dubbo代码:

    //package org.apache.dubbo.common.config;
    
    public abstract class AbstractPrefixConfiguration implements Configuration {
        protected String id;
        protected String prefix;
    
        public AbstractPrefixConfiguration(String prefix, String id) {
            if (StringUtils.isNotEmpty(prefix) && !prefix.endsWith(".")) {
                this.prefix = prefix + ".";
            } else {
                this.prefix = prefix;
            }
            this.id = id;
        }
    
        @Override
        public Object getProperty(String key, Object defaultValue) {
            Object value = null;
            if (StringUtils.isNotEmpty(prefix)) {
                if (StringUtils.isNotEmpty(id)) {
                    value = getInternalProperty(prefix + id + "." + key);
                }
                if (value == null) {
                    value = getInternalProperty(prefix + key);
                }
            } else {
                value = getInternalProperty(key);
            }
            return value != null ? value : defaultValue;
        }
    }
    

    已知Dubbo是通过Configuration 的getProperty获取version等等这些属性,
    这里可以看到用prefix + key的方式作为 property的名字来获取变量的值。
    经过Debug发现,Dubbo的 AbstractPrefixConfiguration类的prefix正好是接口的FQCN,在本例中为:

    AbstractPrefixConfiguration.prefix=dubbo.service.io.github.slankka.provider.IAuthApi.
    

    那么key=version
    因此可以推断出,Dubbo的外部化配置指定的Namespace中,如果要指定版本,且希望经过Dubbo的Environment处理,那么一定要用这种形式:

    dubbo.service.io.github.slankka.provider.IAuthApi.version=20000
    

    总结

    1. 如果使用placeholder的方式定义Service版本,那么根据习惯,要确保这些变量放在Spring启动阶段就能读到的地方。
    2. 如果要在Dubbo的namespace中定义,被Dubbo处理,那么要符合Dubbo的命令规则。dubbo.service.xxxxxxx.version等等这种形式。
    3. 如果使用placeholder的方式定义,但希望被Apollo直接处理,那么需要配置:
    apollo.bootstrap.enabled = true
    apollo.bootstrap.namespaces = application,dubbo
    

    那么什么时候使用 placeholder什么时候使用 dubbo.service..version方式定义呢?

    答案很显然是,如果多个接口都用共用同一个版本变量进行设置,用Apollo+Spring的方式进行处理。如果每一个接口都配置不同的版本,可以用Dubbo的方式定义。

    进一步了解Dubbo和Apollo集成的遇到的有趣问题

    解决Dubbo 2.7.3版本使用ConfigCenterConfig集成Apollo No Provider found的问题

  • 相关阅读:
    NHibernate初学遇到的问题及解决方案之一
    MSSQL2005数据库备份时提示:System.Data.SqlClient.SqlError: 媒体集有 2 个媒体簇,但只提供了 1 个。 .
    VS自带的ASP.NET web服务器Cassini源代码
    Python开发WebService使用soaplib库
    vue入门创建项目
    vue回顾Object.defineproperty方法
    虚拟机ping不通百度的解决方案
    zookeeper完全分布式环境部署
    vue+echarts生成图表步骤
    虚拟机时间同步
  • 原文地址:https://www.cnblogs.com/slankka/p/11777035.html
Copyright © 2011-2022 走看看