Spring Cloud 微服务公共配置处理

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

配置文件的敏感数如数据库地址和账号信息,据呈现在每个配置文件中,替换起来需要一个个配置文件进行修改。

各个微服务配置文件存在很多冗余配置(如Eureka,Feign),一旦这些部分调整,需要针对每个微服务进行调整,运维压力大增。

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

Spring Cloud 微服务公共配置处理

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

:8021/common_rent/dev/aliyun_dev

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

代码示例:

拦截器实现

@Component @Aspect public class ResourceLoaderInterceptor { private static Log logger = LogFactory.getLog(ResourceLoaderInterceptor.class); @Resource ExternalProperties 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<String, Object>) propertySource.getSource()); } } } } catch (Throwable throwable) { logger.error(ExceptionUtils.getStackTrace(throwable)); } finally { stopWatch.stop(); System.out.println(stopWatch.getTotalTimeMillis()); } return returnObj; } private void placeHolderResolve(Map<String, Object> source) { Map<String, Object> 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<String, Object> collectConfigSet() { Map<String, Object> 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; } }

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; } }

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。