千家信息网

Spring Cloud 微服务公共配置处理

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,Spring Cloud Config Server提供了微服务获取配置的功能,这些配置文件(application.yml或者application.properties)通常维护在git或者数据库
千家信息网最后更新 2026年11月01日Spring Cloud 微服务公共配置处理

Spring Cloud Config Server提供了微服务获取配置的功能,这些配置文件(application.yml或者application.properties)通常维护在git或者数据库中,而且支持通过RefreshScope动态刷新,使用起来还是比较灵活的。但是当微服务越来越多时,会遇到下面几个问题:

  1. 配置文件的敏感数如数据库地址和账号信息,据呈现在每个配置文件中,替换起来需要一个个配置文件进行修改。
  2. 各个微服务配置文件存在很多冗余配置(如Eureka,Feign),一旦这些部分调整,需要针对每个微服务进行调整,运维压力大增。

为了解决上述问题,我们可以从configServer服务着手进行改造,示意如下:

不同的服务ABC,不管是在配置中心仓库端配置了多少个文件,从ConfigServer返回的,一定是服务最终应用的配置。获取配置的方式,通常是调用ConfigServer的一个地址,如:

http://localhost:8021/common_rent/dev/aliyun_dev

common_rent是application name,dev是profile,aliyun_dev是label(git的分支)。这个地址的处理接口,是ConfigServer的EnvironmentController,所以通过拦截这个接口,将敏感信息或者公共配置抽取到configServer的application.yml, 返回前进行替换或者拼接,即可实现上述目的。

代码示例:

  1. 拦截器实现

    @Component@Aspectpublic class ResourceLoaderInterceptor {private static Log logger = LogFactory.getLog(ResourceLoaderInterceptor.class);@ResourceExternalProperties externalProperties;@Around("execution(* org.springframework.cloud.config.server..*Controller.*(..)) ")public Object commonPropertiesResolve(ProceedingJoinPoint joinPoint) throws Throwable {    Object returnObj = null;    Object[] args = joinPoint.getArgs();    StopWatch stopWatch = new StopWatch();    try {        stopWatch.start();        returnObj = joinPoint.proceed(args);        if (Environment.class.isInstance(returnObj)) {            Environment environment = (Environment) returnObj;            if (environment.getPropertySources() != null && environment.getPropertySources().size() > 0) {                for (PropertySource propertySource : environment.getPropertySources()) {                    placeHolderResolve((Map) propertySource.getSource());                }            }        }    } catch (Throwable throwable) {        logger.error(ExceptionUtils.getStackTrace(throwable));    } finally {        stopWatch.stop();        System.out.println(stopWatch.getTotalTimeMillis());    }    return returnObj;}private void placeHolderResolve(Map source) {    Map placeHolders = collectConfigSet();    for (String key : source.keySet()) {        Object value = source.get(key);        Object valueAfterReplace = null;        if (value != null) {            if (String.class.isInstance(value) && ((String) value).contains("${ext.")) {                String varExp = (String) value;                for (String variable : placeHolders.keySet()) {                    String vk = "${" + variable + "}";                    if (varExp.contains(vk)) {                        Object replaceValue = placeHolders.get(variable);                        if (replaceValue != null) {                            if (varExp.equalsIgnoreCase(vk)) {                                valueAfterReplace = replaceValue;                                break;                            } else {                                varExp = StringUtils.replace(varExp, vk, "" + replaceValue);                                if (!varExp.contains("${")) {                                    break;                                }                            }                        } else {                            logger.error("Property " + vk + " is not properly configured!");                        }                    }                }                if (valueAfterReplace != null) {                    source.put(key, valueAfterReplace);                } else if (varExp.contains("${")) {                    logger.error("Property " + varExp + " is not properly configured!");                } else {                    source.put(key, varExp);                }            }        }    }}private Map collectConfigSet() {    Map placeHolders = new HashMap<>();    Field[] fields = ExternalProperties.class.getDeclaredFields();    for (int i = 0; i < fields.length; i++) {        try {            Field propertiesField = fields[i];            ResourcePrefix resourcePrefix = propertiesField.getAnnotation(ResourcePrefix.class);            String prefix = resourcePrefix.value();            ExtDataSource extDataSource = (ExtDataSource) BeanUtils.getPropertyDescriptor(ExternalProperties.class, propertiesField.getName()).getReadMethod().invoke(externalProperties);            if (extDataSource != null) {                Field[] fields2 = ExtDataSource.class.getDeclaredFields();                for (Field datasourceField : fields2) {                    try {                        ResourcePrefix annotation = datasourceField.getAnnotation(ResourcePrefix.class);                        String suffix = annotation.value();                        Object sourceFieldValue = BeanUtils.getPropertyDescriptor(ExtDataSource.class, datasourceField.getName()).getReadMethod().invoke(extDataSource);                        if (sourceFieldValue != null) {                            placeHolders.put(prefix + "." + suffix, sourceFieldValue);                        }                    } catch (Exception e) {                        logger.error(ExceptionUtils.getStackTrace(e));                    }                }            }        } catch (Exception e) {            logger.error(ExceptionUtils.getStackTrace(e));        }    }    return placeHolders;}}
  2. ExternalProperites实现
@ConfigurationProperties(prefix = "external", ignoreUnknownFields = true)public class ExternalProperties implements Serializable {    @ResourcePrefix(value = "ext.spring.datasource")    private ExtDataSource datasource;    @ResourcePrefix(value = "ext.spring.data.mongodb")    private ExtDataSource mongodb;    @ResourcePrefix(value = "ext.spring.redis")    private ExtDataSource redis;    @ResourcePrefix(value = "ext.spring.rabbitmq")    private ExtDataSource rabbitmq;    public ExtDataSource getDatasource() {        return datasource;    }    public void setDatasource(ExtDataSource datasource) {        this.datasource = datasource;    }    public ExtDataSource getRabbitmq() {        return rabbitmq;    }    public void setRabbitmq(ExtDataSource rabbitmq) {        this.rabbitmq = rabbitmq;    }    public ExtDataSource getMongodb() {        return mongodb;    }    public void setMongodb(ExtDataSource mongodb) {        this.mongodb = mongodb;    }    public ExtDataSource getRedis() {        return redis;    }    public void setRedis(ExtDataSource redis) {        this.redis = redis;    }}
  1. ExtDataSource实现

    public class ExtDataSource {@ResourcePrefix(value = "host")private String host;@ResourcePrefix(value = "port")private Integer port;@ResourcePrefix(value = "url")private String url;@ResourcePrefix(value = "uri")private String uri;@ResourcePrefix(value = "username")private String userName;@ResourcePrefix(value = "password")private String password;public String getUrl() {    return url;}public void setUrl(String url) {    this.url = url;}public String getHost() {    return host;}public void setHost(String host) {    this.host = host;}public Integer getPort() {    return port;}public void setPort(Integer port) {    this.port = port;}public String getUri() {    return uri;}public void setUri(String uri) {    this.uri = uri;}public String getUserName() {    return userName;}public void setUserName(String userName) {    this.userName = userName;}public String getPassword() {    return password;}public void setPassword(String password) {    this.password = password;}}
  2. ResourcePrefix实现
    @Target({ElementType.FIELD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface ResourcePrefix {String value();}

然后在configServer的application.yml中增加相关信息,如

external:  datasource:    host: 122.122.111.111    port: 3307    userName: usr    password: pwd  mongodb:    host: 122.122.111.111    port: 20467    uri: 122.122.111.111:20467,122.122.111.112:20467,122.122.111.112:20467    userName: usr    password:  pwd  redis:    uri: 122.122.111.113:6379,122.122.112.113:6379,122.122.111.113:6379    password: redispassword  rabbitmq:    host: 122.122.111.113    port: 20467    userName: usr    password: pwd

将ServiceA的配置文件serviceA_dev.yml中的数据库相关信息替换成变量,以mysql为例
spring.datasource.uri: url: jdbc:mysql://#{ext.spring.datasource.host}:#{ext.spring.datasource.port}/dbName?useUnicode=true&characterEncoding=utf8,
serviceB和serviceC配置文件做同样处理,即可实现一次性替换。

后续如果需要增加公共配置,可以直接在ConfigServer的配置中间中增加,调整下拦截器的实现逻辑即可。

配置 文件 服务 信息 地址 数据 数据库 调整 处理 接口 拦截器 不同 一次性 仓库 代码 冗余 几个问题 分支 功能 动态 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 重生之互联网科技帝国 厦门中拓互联网络科技有限公司 广州凡科互联网科技 四个字互联网科技公司取名 滨湖区互联网智能科技产品供应 农村开互联网科技讲堂 欧洲十大科技互联网公司 中化能源互联网科技招聘 成都铂石互联网科技做什么的 广西互联网科技孵化中心 上海京穆互联网科技有限公司 上海钢联属于互联网科技股吗 图游互联网科技 信承诺互联网科技有限公司 互联网科技手机排行榜 陕西九四连强互联网科技有限公司 美国五大互联网科技公司市值多少 每日互联网科技新闻 科技发展第三阶段互联网时代 小牛互联网科技有限公司地址 互联网高科技 上海挚品互联网科技有限公司 上海睿民互联网科技有限公司 喔噻互联网科技 嘟嘟瓜互联网科技 小马过河互联网科技 佛山市翊博互联网络科技有限公司 山东有哪些互联网科技公司 互联网营销推广黑科技 中国主要互联网科技公司
0