SpringCloud微服務(wù)公共配置處理

Spring Cloud Config Server提供了微服務(wù)獲取配置的功能,這些配置文件(application.yml或者application.properties)通常維護(hù)在git或者數(shù)據(jù)庫(kù)中,而且支持通過RefreshScope動(dòng)態(tài)刷新,使用起來還是比較靈活的。但是當(dāng)微服務(wù)越來越多時(shí),會(huì)遇到下面幾個(gè)問題:

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)蒙山免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

  1. 配置文件的敏感數(shù)如數(shù)據(jù)庫(kù)地址和賬號(hào)信息,據(jù)呈現(xiàn)在每個(gè)配置文件中,替換起來需要一個(gè)個(gè)配置文件進(jìn)行修改。
  2. 各個(gè)微服務(wù)配置文件存在很多冗余配置(如Eureka,F(xiàn)eign),一旦這些部分調(diào)整,需要針對(duì)每個(gè)微服務(wù)進(jìn)行調(diào)整,運(yùn)維壓力大增。

為了解決上述問題,我們可以從configServer服務(wù)著手進(jìn)行改造,示意如下:
Spring Cloud 微服務(wù)公共配置處理

不同的服務(wù)ABC,不管是在配置中心倉(cāng)庫(kù)端配置了多少個(gè)文件,從ConfigServer返回的,一定是服務(wù)最終應(yīng)用的配置。獲取配置的方式,通常是調(diào)用ConfigServer的一個(gè)地址,如:

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

common_rent是application name,dev是profile,aliyun_dev是label(git的分支)。這個(gè)地址的處理接口,是ConfigServer的EnvironmentController,所以通過攔截這個(gè)接口,將敏感信息或者公共配置抽取到configServer的application.yml, 返回前進(jìn)行替換或者拼接,即可實(shí)現(xiàn)上述目的。

代碼示例:

  1. 攔截器實(shí)現(xiàn)

    @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;
    }
    }
  2. ExternalProperites實(shí)現(xiàn)
@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實(shí)現(xiàn)

    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實(shí)現(xiàn)
    @Target({ElementType.FIELD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ResourcePrefix {
    String value();
    }

然后在configServer的application.yml中增加相關(guān)信息,如

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中的數(shù)據(jù)庫(kù)相關(guān)信息替換成變量,以MySQL為例
spring.datasource.uri: url: jdbc:mysql://#{ext.spring.datasource.host}:#{ext.spring.datasource.port}/dbName?useUnicode=true&characterEncoding=utf8,
serviceB和serviceC配置文件做同樣處理,即可實(shí)現(xiàn)一次性替換。

后續(xù)如果需要增加公共配置,可以直接在ConfigServer的配置中間中增加,調(diào)整下攔截器的實(shí)現(xiàn)邏輯即可。

網(wǎng)頁(yè)名稱:SpringCloud微服務(wù)公共配置處理
轉(zhuǎn)載來源:http://muchs.cn/article14/ihdede.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司自適應(yīng)網(wǎng)站、企業(yè)網(wǎng)站制作網(wǎng)頁(yè)設(shè)計(jì)公司、服務(wù)器托管、企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站制作