玩轉Spring Cloud之配置中心(config server &config client)

 本文內容導航:css

1、搭建配置服務中心(config server)html

  1.1.git方式java

  1.2.svn方式python

  1.3.本地文件方式git

  1.4.解決配置中包含中文內容返回亂碼問題github

2、搭建配置消費客戶端(config client)web

  2.1.經過@value方式獲取配置信息spring

  2.2.經過建立一個映射遠程配置信息的Bean(RemoteConfigProperties) 方式獲取配置信息sql

  2.3.經過Environment來直接獲取配置信息數據庫

  2.4.實現配置信息自動刷新

  2.5.加入到註冊中心配置成高可用集羣環境

 

上篇總結了熔斷降級(Hystrix)與監控的使用方式,裏面涉及到的一些重點的知識細節我都有說明,網上不少的spring cloud教程只是簡單的貼代碼、簡單描述,而個人文章是要體現知識的積累與開發時的參考,故花了一些時間描述了一些細節,這些細節能幫助我本身(夢在旅途)以及你們少走彎路,本文仍然圍繞這個中心思想來總結描述關於配置中心的搭建與使用,實現了多種搭建配置服務中心(config server),也實現了多種配置消費客戶端的實現方式。(多種配置消費方式目前不多有人總結,而我在本文中有特別介紹,不必定都用得上,但應該要了解,以便觸類旁通靈活運用),好了廢話很少說,直接開始本文主題。

首先咱們要了解,爲何須要配置中心?配置中心能解決什麼問題?回答這些問題能夠參見:https://www.cnblogs.com/xiaoqi/p/configserver-compair.html,我這裏簡要說明一下:JAVA應用通常經常使用的配置文件是:xxx.Properties 或 xxx.yml文件,.NET(.NET CORE)通常經常使用的配置文件是:xxx.config 或 xxx.json 甚至是xxx.ini,它們都可以很好的應對單機本地配置的需求(能夠多個應用共用同一個目錄位置的配置文件),但若是是分佈式應用,那麼本地配置文件在某些場景下就顯得不那麼合適了,由於一是存在配置冗餘(不一樣機器上配置相同的配置信息),二是沒法快速同步配置信息(若是要更改配置信息,就得每臺服務器一臺一臺的更改,或使用文件同步機制稍微能保證儘快同步),三是沒有多版本管理,出現更新配置後有問題沒法快速回滾(若有問題,需從新配置或人爲將以前的備份的配置文件一臺臺服務器更新或文件同步到多臺服務器),好比:數據庫鏈接字符串,若是使用本地配置就存在如上說的三點問題,正由於存在這些問題,因此纔有了分佈式配置中心框架來解決這些問題。

 分佈式配置中心的主流框架有不少,因爲本文是總結spring cloud系列的文章,故這裏經過DEMO來實現分佈式配置中心Server端及Client消費端(讀取配置),並確保高可用。

1、搭建配置服務中心(config server)

  首先經過IDEA spring initializer(或直接經過https://start.spring.io/)建立一個spring boot項目(demo項目命名:configserver),建立過程當中選擇:config server依賴,生成項目後的POM XML文件以下:(若是缺乏依賴請自行手動添加)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>cn.zuowenjun.cloud</groupId>
    <artifactId>configserver</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>configserver</name>
    <url>http://www.zuowenjun.cn</url>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <!--spring cloud配置中心依賴[默認GIT]-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <jvmArguments>-Dfile.encoding=UTF-8</jvmArguments>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>
View Code

  而後下面分別介紹經過三種方式來實現配置中心:(注意三種方式均使用上面的項目初始環境,下面再也不介紹

  1.1.git方式(即:將GIT倉庫【GITHUB、GITLAB、 GITEE等】做爲配置集中存儲的介質)

    前提工做:既然是使用GIT倉庫做爲配置存儲,那咱們首先就得在相關的GIT站點上建立用於存放config信息的倉庫,如我(夢在旅途)在本身的github上建立了一個learning-demos/config倉庫目錄,而後在config目錄下分別建立兩個環境的配置文件(http://configclient-dev.properties、http://configclient-prod.properties),配置文件命名規則應儘量使用:{application}-{profile}.{properties|yml},以下是GIT中兩個文件配置的演示內容:(演示倉庫地址:https://github.com/zuowj/learning-demos

--configclient-dev.properties內容:測試環境

demo-config-profile-env=dev
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190226.AAAXX66
zuowenjun.skills=.net,java,html,js,css,sql,python,vb--20190226.BBBXX66
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;--20190226.CCCXX1

--configclient-prod.properties內容:生產環境

demo-config-profile-env=prod
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com,http://github.com/zuowj
zuowenjun.skills=.net,java,html,js,css,sql,python,vb
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;學無止境;機會是留給有準備的人
View Code

  1.1.1.在spring boot啓動類(ConfigserverApplication)上添加@EnableConfigServer註解,代碼以下:

package cn.zuowenjun.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@EnableConfigServer
@SpringBootApplication
public class ConfigserverApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigserverApplication.class, args);
    }

}
View Code

  1.1.2.在配置文件(application.yml,固然也能夠是application.properties看我的喜愛,本系列均採用yml)中進行以下配置,重點關注spring.cloud.config節點,相關配置參數有註釋說明:

spring:
  application:
    name: configserver
  profiles:
    active: git #設置使用本地配置(默認是git,能夠設置:subversion(SVN),native(本地))
  cloud:
    config:
      server:
        #以下是GIT配置
        git:
          uri: https://github.com/zuowj/learning-demos     # 配置git倉庫的地址(最後不須要帶/,不然會出現:No custom http config found for URL: XXX)
          search-paths: config                             # git倉庫地址下的相對搜索地址(可用使用通配符),能夠配置多個,用,分割。能夠{application}實現按應用查配置
          username:                                             # git倉庫的帳號(公開倉庫無需帳號信息)
          password:                                             # git倉庫的密碼(公開倉庫無需帳號信息)
          default-label: master                             #git默認分支

  經過上述簡單的兩步即完成搭建基於GIT的配置服務中心,啓動運行項目,GIT倉庫中的配置文件會被自動轉換成當前項目的web api,若需訪問查看遠程配置數據能夠參照如下的規則:

/{application}/{profile}[/{label}]
[/{label}]/{application}-{profile}{.yml|.properties|.json}

  規則簡單說明:{application}=配置消費方應用名稱(即:config client的項目名,通俗講:就是誰用這個配置就是誰的名字),{profile}=配置環境(如:dev開發環境,test測試環境,prod生產環境),{label}=倉庫分支名(git或svn方式指定,native本地方式無需指定),.yml|.properties|.json表示指定的響應返回格式,{}表示必需,[]表示可選,|表示或的關係,例如本Demo項目訪問:

  http://localhost:8866/configclient/dev 、http://localhost:8866/configclient/dev/master

  http://localhost:8866/configclient-dev.yml、http://localhost:8866/configclient-dev.properties、http://localhost:8866/configclient-dev.json、http://localhost:8866/master/configclient-dev.yml

  最終能夠根據訪問URL規則返回相應的內容,相似以下:

//request: http://localhost:8866/configclient-dev.yml

demo-config-profile-env: dev
zuowenjun:
  motto: Learning is endless; Opportunity is for the prepared mind;--20190226.CCCXX1
  site: http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190226.AAAXX66
  skills: .net,java,html,js,css,sql,python,vb--20190226.BBBXX66

//request: http://localhost:8866/configclient-dev.properties

demo-config-profile-env: dev
zuowenjun.motto: Learning is endless; Opportunity is for the prepared mind;--20190226.CCCXX1
zuowenjun.site: http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190226.AAAXX66
zuowenjun.skills: .net,java,html,js,css,sql,python,vb--20190226.BBBXX66

//request: http://localhost:8866/configclient-dev.json
{"demo-config-profile-env":"dev","zuowenjun":{"motto":"Learning is endless; Opportunity is for the prepared mind;--20190226.CCCXX1","site":"http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190226.AAAXX66","skills":".net,java,html,js,css,sql,python,vb--20190226.BBBXX66"}}

//request: http://localhost:8866/configclient/dev

{"name":"configclient","profiles":["dev"],"label":null,"version":"d4616a65c8429b9dd3a67ff226b125ae6a0959bb","state":null,"propertySources":[{"name":"https://github.com/zuowj/learning-demos/config/configclient-dev.properties","source":{"zuowenjun.skills":".net,java,html,js,css,sql,python,vb--20190226.BBBXX66","zuowenjun.site":"http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190226.AAAXX66","demo-config-profile-env":"dev","zuowenjun.motto":"Learning is endless; Opportunity is for the prepared mind;--20190226.CCCXX1"}}]}
View Code

   能夠看到GIT中的配置信息經過config server的API可以正常返回,表示搭建成功,另外須要注意的是若是配置文件中包含中文,那麼可能中文返回的就是亂碼了,上面若是瀏覽prod生產環境【生產環境我特地配置了中文】,如:http://localhost:8866/configclient/prod,那麼中文就會亂碼,解決方案後面會說明,此處瞭解有這個狀況便可。

  1.2.svn方式(即:將SVN倉庫做爲配置集中存儲的介質)

    前提工做:如同GIT方式同樣,要使用SVN倉庫做爲配置存儲,那就須要SVN服務器,將建立用於存放config信息的倉庫,如我(夢在旅途)在SVN服務器建立了app-config倉庫目錄,而後在trunk主幹中仍然添加兩個配置文件(dev,prod)與GIT方式文件名相同,內容以下(內容與GIT方式也基本相同,只是稍微改變內容以便區分):(演示倉庫地址:http://svnhost:port/svn/app-config/trunk)

--configclient-dev.properties內容:

demo-config-profile-env=dev-svn
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190227
zuowenjun.skills=.net,java,html,js,css,sql,python,vb--20190227
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;--20190227

--configclient-prod.properties內容:

demo-config-profile-env=prod-svn
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com,http://github.com/zuowj
zuowenjun.skills=.net,java,html,js,css,sql,python,vb
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;學無止境;機會是留給有準備的人
View Code

  1.2.1.因爲GIT是默認的實現方式,當引入spring-cloud-config-server時,它就具有了相關的框架處理能力,而這裏使用SVN,就須要在POM XML中除了添加config-server依賴外還需單獨添加SVN實現方式的依賴,配置以下:

        <!--spring cloud配置中心依賴[默認GIT]-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <!--使用SVN做爲配置中心依賴-->
        <dependency>
            <groupId>org.tmatesoft.svnkit</groupId>
            <artifactId>svnkit</artifactId>
        </dependency>

   1.2.2.在配置文件(application.yml)中進行以下配置,仍然重點關注spring.cloud.config節點,相關配置參數有註釋說明:

server:
  port: 8866

spring:
  application:
    name: configserver
  profiles:
    active: subversion #設置使用本地配置(默認是git,能夠設置:subversion(SVN),native(本地))
  cloud:
    config:
      server:
        #以下是SVN配置
        svn:
          uri: http://svnhost:port/svn/app-config #SVN倉庫地址
          username: svnuser #SVN帳號(若是沒有權限可爲空)
          password: svnpassword #SVN密碼(若是沒有權限可爲空)
          default-label: trunk #默認SVN分支

  經過上述簡單的兩步即完成搭建基於SVN的配置服務中心,啓動運行項目,SVN倉庫中的配置文件會被自動轉換成當前項目的web api,訪問路徑與GIT方式徹底相同在此不重述。(參照1.1.2訪問URL,能夠獲得SVN倉庫trunk分支裏配置文件配置信息的內容)

  1.3.本地文件方式(即:將config server項目全部服務器的本地文件存放目錄做爲配置集中存儲的介質)

  1.3.1.先在config server項目文件服務器建立指定存放配置的目錄,如本demo是直接建立在項目的resources/configs目錄,仍然是建立與GIT相同的兩個配置文件(dev、prod),配置內容以下:

--configclient-dev.properties內容:

demo-config-profile-env=dev-native
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com--20190227
zuowenjun.skills=.net,java,html,js,css,sql,python,vb--20190227
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;--20190227

--configclient-prod.properties內容:

demo-config-profile-env=prod-native
zuowenjun.site=http://www.zuowenjun.cn,http://zuowj.cnblogs.com,http://github.com/zuowj
zuowenjun.skills=.net,java,html,js,css,sql,python,vb
zuowenjun.motto=Learning is endless; Opportunity is for the prepared mind;學無止境;機會是留給有準備的人
View Code

  1.3.2.在配置文件(application.yml)中進行以下配置,仍然重點關注spring.cloud.config節點,相關配置參數有註釋說明:(很簡單,只須要設置profiles.active=native,而後在native節點設置查找配置的存放目錄便可)

server:
  port: 8866

spring:
  application:
    name: configserver
  profiles:
    active: native #設置使用本地配置(默認是git,能夠設置:subversion(SVN),native(本地))
  cloud:
    config:
      server:
        #以下是本地文件配置
        native:
          search-locations: classpath:/configs #配置文件存放的目錄

  經過上述簡單的兩步即完成搭建基於本地文件的配置服務中心,啓動運行項目,存放的配置文件會被自動轉換成當前項目的web api,訪問路徑與GIT方式徹底相同在此不重述。(參照1.1.2訪問URL,能夠獲得本地文件配置信息的內容)

  1.4.解決配置中包含中文內容返回亂碼問題(此處實現方式參照網上說明,在此只是集中說明,便於你們理解)--均適用於以上三種方式

   亂碼緣由及解決方案思路可參見:https://blog.csdn.net/sinat_38843093/article/details/79960777?utm_source=blogxgwz4,但因爲最新版本的spring boot的PropertySourceLoader接口定義有些不一樣故我這裏參照該文進行完善並最終解決亂碼。

  首先自定義一個實現了PropertySourceLoader的類:MyPropertySourceLoader,並實現接口的方法邏輯,具體代碼以下:(最重要的代碼是:properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8));即表示使用UTF8的字符集來讀取配置文件流信息)

package cn.zuowenjun.cloud;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class MyPropertySourceLoader implements PropertySourceLoader {
    private Logger logger= LoggerFactory.getLogger(MyPropertySourceLoader.class);

    @Override
    public String[] getFileExtensions() {
        return new String[]{"properties", "xml"};
    }

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        Properties properties=new Properties();
        InputStream inputStream=null;
        try{
            inputStream=resource.getInputStream();
            properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        }catch (IOException ioEx){
            logger.error("load inputStream failed",ioEx);
            throw ioEx;
        }
        catch (Exception e){
            logger.error("load inputStream failed",e);
        }finally {
            if(inputStream!=null){
                inputStream.close();
            }
        }

        List<PropertySource<?>> propertySourceList=null;
        if (!properties.isEmpty()) {

            PropertiesPropertySource propertiesPropertySource = new PropertiesPropertySource(name, properties);
            propertySourceList=  new ArrayList<>();
            propertySourceList.add(propertiesPropertySource);
        }
        return  propertySourceList;

    }


}
View Code

  而後在resources目錄下建立META-INF目錄,而後在該目錄中建立spring.factories文件(這裏spring boot的擴展配置文件),在該文件中輸入以下內容便可:

org.springframework.boot.env.PropertySourceLoader=cn.zuowenjun.cloud.MyPropertySourceLoader

若想了解spring.factories相關信息,可參考:https://blog.csdn.net/lvoyee/article/details/82017057 、 https://blog.csdn.net/boling_cavalry/article/details/83048588

 經過上述步驟,如今不管是哪一種方式訪問配置中心的API,若涉及中文都能正常返回不會亂碼,以下圖所示:(固然若是使用[/{label}]/{application}-{profile}{.yml|.properties|.json}這種方式訪問可能還會出現亂碼,具體緣由我還未了解,求大神們指點,但目前已不影響配置消費【即:配置消費方獲取到的中文信息均是正常不會亂碼】)

  

2、搭建配置消費客戶端(config client)

  首先經過IDEA spring initializer(或直接經過https://start.spring.io/)搭建spring boot + spring MVC(Rest API)空項目,建立過程當中選擇:web、config client依賴,最後生成的POM XML文件以下:(若是缺乏依賴請自行手動添加)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.zuowenjun.cloud</groupId>
    <artifactId>configclient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>configclient</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

    <dependencies>
        <!--spring MVC依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--config client依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

        <!--ConfigurationProperties類所需依賴,手動添加的-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

</project>
View Code

  而後在resources目錄下建立bootstrap.yml文件,並在配置文件中添加以下內容:(若是想了解bootstrap與application配置文件二者的區別,請參見:http://www.javashuo.com/article/p-usrshetg-gy.html

server:
  port: 8008

spring:
  application:
    name: configclient

  cloud:
    config:
      name: configclient #對應config server Url中的{application}
      profile: prod #配置環境,對應config server Url中的{profile}
      #label: trunk #配置分支(不配置則默認:git則是master,svn則是trunk),
      uri: http://localhost:8866 #配置中心地址

  最後下面分別介紹實現各類不一樣的配置消費(讀取配置)方式:(注意均使用上面的項目初始環境,同時如下的幾種服務配置消費方式都可同時並存在一個項目中)

  2.1.經過@value方式獲取配置信息

    這種最爲簡單,網上也大部份是這種,我這裏爲了便於區分配置屬性與controller自己使用了繼承的方式(注意,我這裏用繼承而沒有使用單獨定義一個RemoteConfig配置類+Value,是由於經我驗證發現將會影響配置自動刷新,具體緣由還未查清,初步判斷與加上@RefreshScope註解上生成的代理類有關係),代碼結構更清晰,實現代碼以下:

package cn.zuowenjun.cloud.model;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;


public abstract class RemoteConfig {

    @Value("${demo-config-profile-env}")
    public String profileEnv;

    @Value("${zuowenjun.site}")
    public String zwjSite;

    @Value("${zuowenjun.skills}")
    public String zwjSkills;

    @Value("${zuowenjun.motto}")
    public String zwjMotto;
}



package cn.zuowenjun.cloud.Controller;

import cn.zuowenjun.cloud.model.RemoteConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/demo")
public class DemoController extends RemoteConfig {


    @RequestMapping("/config/byval")
    public Object getRemoteConfigByValue(){
        Map<String,Object> model=new HashMap<>();
        model.put("getMode","@Value");

        Map<String,String> remoteCgfMap=new HashMap<>();
        remoteCgfMap.put("profileEnv", this.profileEnv);
        remoteCgfMap.put("zwjSite", this.zwjSite);
        remoteCgfMap.put("zwjSkills",this.zwjSkills);
        remoteCgfMap.put("zwjMotto", this.zwjMotto);

        model.put("remoteConfig",remoteCgfMap);


        return model;
    }



}

  如上代碼所示,咱們只需在類成員字段上標記@Value註解,並指定要獲取的配置中心上配置項的名稱便可。運行項目,訪問:http://localhost:8008/demo/config/byval,便可響應返回獲取到的config信息,以下圖示:

  2.2.經過建立一個映射遠程配置信息的Bean(RemoteConfigProperties) 方式獲取配置信息

  首先定義一個映射遠程配置信息的Bean類:RemoteConfigProperties,該類中全部的屬性名均需與配置中心上配置文件的配置內容相同(名字以及層級都需相同,若配置項名稱有-,則配置類中請忽略直接拼接命名便可但需符合lowerCamelCase,如:demo-config-profile-env,則字段名爲:demoConfigProfileEnv,若是屬性中有點( . ),則應視爲點後面的部分爲下級,應再定義相關的配置映射類),該類完整代碼以下:

package cn.zuowenjun.cloud.model;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties()//若是有前綴,則能夠設置prefix=XXX
public class RemoteConfigProperties {

    private String demoConfigProfileEnv;
    private Zuowenjun zuowenjun;

    public String getDemoConfigProfileEnv() {
        return demoConfigProfileEnv;
    }

    public void setDemoConfigProfileEnv(String demoConfigProfileEnv) {
        this.demoConfigProfileEnv = demoConfigProfileEnv;
    }

    public Zuowenjun getZuowenjun() {
        return zuowenjun;
    }

    public void setZuowenjun(Zuowenjun zuowenjun) {
        this.zuowenjun = zuowenjun;
    }

    public static class Zuowenjun {

        private String site;
        private String skills;
        private String motto;


        public String getSite() {
            return site;
        }

        public void setSite(String site) {
            this.site = site;
        }

        public String getSkills() {
            return skills;
        }

        public void setSkills(String skills) {
            this.skills = skills;
        }

        public String getMotto() {
            return motto;
        }

        public void setMotto(String motto) {
            this.motto = motto;
        }

    }

}

如上代碼所示,屬性字段名與配置項的命名保持一致,如有下級則定義下級的配置類,這裏下級配置類(Zuowenjun)採用了內部靜態類的方式(注意這裏若是是內部類,必定是static,而不能是普通的class,由於內部普通類與內部靜態類是有區別的,具體可參見:java 內部類和靜態內部類的區別),也能夠單獨定義一個類,同時在配置類上標記了@ConfigurationProperties(這指明瞭該類是配置映射類),@Component這個不用說了吧就是表示能自動被spring IOC容器掃描並註冊。

  而後在DemoController中增長字段注入該類:RemoteConfigProperties,並添加用於讀取RemoteConfigProperties類中的配置信息的方法(getRemoteConfigByPropertiesBean),具體代碼以下:(這裏保留了@Value方式的代碼)

package cn.zuowenjun.cloud.Controller;

import cn.zuowenjun.cloud.model.RemoteConfig;
import cn.zuowenjun.cloud.model.RemoteConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/demo")
public class DemoController extends RemoteConfig {


    @Autowired
    private RemoteConfigProperties remoteConfigProperties;

    @RequestMapping("/config/byval")
    public Object getRemoteConfigByValue(){
        Map<String,Object> model=new HashMap<>();
        model.put("getMode","@Value");

        Map<String,String> remoteCgfMap=new HashMap<>();
        remoteCgfMap.put("profileEnv", this.profileEnv);
        remoteCgfMap.put("zwjSite", this.zwjSite);
        remoteCgfMap.put("zwjSkills",this.zwjSkills);
        remoteCgfMap.put("zwjMotto", this.zwjMotto);

        model.put("remoteConfig",remoteCgfMap);


        return model;
    }

    @RequestMapping("/config/byprops")
    public Object getRemoteConfigByPropertiesBean(){
        Map<String,Object> model=new HashMap<>();
        model.put("getMode","Properties Bean");
        model.put("remoteConfig",remoteConfigProperties);
        return model;
    }



}
View Code

  最後啓動運行項目,訪問:http://localhost:8008/demo/config/byprops,便可響應返回獲取到的config信息,以下圖示:

  2.3.經過Environment來直接獲取配置信息

    其實上面2種方式底層都是使用這種方式來獲取配置信息的只是包裝了後你們無需關心而矣,核心是經過environment.getProperty方法來獲取對應的配置信息的,這種方式只需在DemoController增長字段注入Environment的實例,而後添加一個從Environment獲取配置信息的方法便可(getRemoteConfigByEnv),具體代碼以下:(保留@Value方式、映射遠程配置信息的Bean(RemoteConfigProperties) 方式)

package cn.zuowenjun.cloud.Controller;

import cn.zuowenjun.cloud.model.RemoteConfig;
import cn.zuowenjun.cloud.model.RemoteConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;


@RestController
@RequestMapping("/demo")
public class DemoController extends RemoteConfig {


    @Autowired
    private Environment environment;

    @Autowired
    private RemoteConfigProperties remoteConfigProperties;

    @RequestMapping("/config/byval")
    public Object getRemoteConfigByValue(){
        Map<String,Object> model=new HashMap<>();
        model.put("getMode","@Value");

        Map<String,String> remoteCgfMap=new HashMap<>();
        remoteCgfMap.put("profileEnv", this.profileEnv);
        remoteCgfMap.put("zwjSite", this.zwjSite);
        remoteCgfMap.put("zwjSkills",this.zwjSkills);
        remoteCgfMap.put("zwjMotto", this.zwjMotto);

        model.put("remoteConfig",remoteCgfMap);


        return model;
    }

    @RequestMapping("/config/byprops")
    public Object getRemoteConfigByPropertiesBean(){
        Map<String,Object> model=new HashMap<>();
        model.put("getMode","Properties Bean");
        model.put("remoteConfig",remoteConfigProperties);
        return model;
    }

    @RequestMapping("/config/byenv")
    public  Object getRemoteConfigByEnv(){
        Map<String,Object> model=new HashMap<>();
        model.put("getMode","Environment");

        Map<String,String> remoteCgfMap=new HashMap<>();
        remoteCgfMap.put("profileEnv", environment.getProperty("demo-config-profile-env"));
        remoteCgfMap.put("zwjSite", environment.getProperty("zuowenjun.site"));
        remoteCgfMap.put("zwjSkills", environment.getProperty("zuowenjun.skills"));
        remoteCgfMap.put("zwjMotto", environment.getProperty("zuowenjun.motto"));

        model.put("remoteConfig",remoteCgfMap);
        return  model;
    }


}
View Code

最後啓動運行項目,訪問:http://localhost:8008/demo/config/byenv,便可響應返回獲取到的config信息,以下圖示:

如上三種方式配置文件均不須要改變,若是須要訪問不一樣的環境,不一樣的分支,則能夠修改項目配置文件bootstrap.yml中對應的屬性:profile、label等,至於配置中心(config server)使用的是哪一種方式存儲配置,配置消費端(config client)無需關心,只管用便可。

  2.4.實現配置信息自動刷新(可參見:)

  2.4.1.在controller類(DemoController)上添加@RefreshScope註解,簡單就不貼代碼

  2.4.2.在POM XML中添加actuator依賴,配置以下:

        <!--actuator監控功能所需依賴(內部包含refresh,動態刷新配置信息須要)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

  2.4.3.在項目配置文件(bootstrap.yml或application.yml均可以)添加以下配置內容:

management:
  endpoints:
    web:
      exposure:
        include: "*" #暴露全部端口,也能夠指定某一個環境(先management.endpoint.{profile}.enabled=true,而後這裏指定這個{profile},多個用,分隔)

  經過上述兩步即完成config client端的自動監聽與刷新機制(刷新原理參見:https://blog.csdn.net/cml_blog/article/details/78411312

  這時能夠啓動運行項目,而後POST請求訪問:http://localhost:8008/actuator/refresh,若是能正常響應結果沒有報404就OK了,響應內容爲空?不要緊,由於只有當config server端的配置文件有更新,這時POST這個API時,即會檢測並響應返回更新的配置項信息,這樣config client內部便可進行配置的刷新工做。到目前尚未實現全自動刷新配置,由於config server端配置文件有更新,config client端並不會第一時間感知到,若是不去POST請求refresh API則不會更新,因此自動更新的關鍵是如何可以實現配置中心的配置文件一旦更改就能通知全部的配置消費端(config client)自動更新配置信息。若是採用github的方式,那麼可使用github倉庫的Webhooks功能,具體操做位置以下圖示:

設置webhooks後,只要這個存配置的GIT倉庫發生改變,將針觸發事件並回調refresh接口(固然能夠封裝一個通用接口,而後裏面把全部的 config client都調refresh接口),config client端收到刷新請求後就會從新從config server中獲取配置信息。

雖然webhooks可以解決自動刷新問題,但仍不夠優美,比較好的實現方式是再結合spring cloud bus、mq實現更好的自動刷新全部config client,具體可參見:http://www.javashuo.com/article/p-mkxfpifl-ev.html 、 http://www.javashuo.com/article/p-wcjlagtu-cz.html

  另外actuator還默認集成了健康檢查功能,可訪問:http://localhost:8866/actuator/health,便可看到響應結果,正常則爲status=UP,不然多是DOWN

  2.5.加入到註冊中心配置成高可用集羣環境

   思路:咱們能夠把服務配置中心(config server)與服務消費客戶端(config client)均做爲服務加入到註冊中內心面,而後服務消費客戶端(config client)經過註冊中心根據服務配置中心(config server)的服務ID(應用名稱)找到config server IP,而後請求該IP便可。

  前提:先把以前文章《玩轉Spring Cloud之服務註冊發現(eureka)及負載均衡消費(ribbon、feign)》中的eureka server項目正常啓動;

  2.5.1.改造服務配置中心(config server),集成eureka client(這個我以前文章有說明)【操做步驟簡要重述:先在POM XML中添加spring-cloud-starter-netflix-eureka-client依賴,而後在spring boot啓動類上添加@EnableDiscoveryClient註解以便啓用服務發現,最後在application.yml中添加eureka client的配置信息】,讓其可以加入到註冊中心中,以下是改造後的配置文件:(註釋掉的是多種方式配置)--eureka 配置節點爲新增

server:
  port: 8866

spring:
  application:
    name: configserver
  profiles:
    active: native #設置使用本地配置(默認是git,能夠設置:subversion(SVN),native(本地))
  cloud:
    config:
      server:
        #以下是GIT配置
#        git:
#          uri: https://github.com/zuowj/learning-demos     # 配置git倉庫的地址(最後不須要帶/,不然會出現:No custom http config found for URL: XXX)
#          search-paths: config                             # git倉庫地址下的相對搜索地址(可用使用通配符),能夠配置多個,用,分割。能夠{application}實現按應用查配置
#          username:                                             # git倉庫的帳號(公開倉庫無需帳號信息)
#          password:                                             # git倉庫的密碼(公開倉庫無需帳號信息)
#          default-label: master                             #git默認分支

        #以下是SVN配置
#        svn:
#          uri: http://svnhost:port/svn/app-config #SVN倉庫地址
#          username: svnuser #SVN帳號(若是沒有權限可爲空)
#          password: svnpassword#SVN密碼(若是沒有權限可爲空)
#          default-label: trunk #默認SVN分支

        #以下是本地文件配置
        native:
          search-locations: classpath:/configs #配置文件存放的目錄

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8800/eureka/
View Code

  2.5.2.改造服務消費客戶端(config client),集成eureka client(同2.5.1的服務配置中心(config server),集成eureka client步驟),讓其可以加入到註冊中心中,以即可以經過註冊中心根據服務配置中心(config server)的服務ID(應用名稱)找到config server IP,這裏的eureka相關配置應統一在bootstrap.yml中,完整配置以下:

server:
  port: 8008

spring:
  application:
    name: configclient

  cloud:
    config:
      name: configclient #對應config server Url中的{application}
      profile: prod #配置環境,對應config server Url中的{profile}
      #label: trunk #配置分支(不配置則默認:git則是master,svn則是trunk),
      #uri: http://localhost:8866 #配置中心地址
      discovery:
        enabled: true #啓用服務發現
        service-id: configserver #指定要從eureka獲取的config server的服務ID(即:configserverr的applicationName)

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8800/eureka/

如上配置,重點是spring.cloud.config.uri再也不指定固定的config server IP,而是改爲配置spring.cloud.config.discovery【服務發現】,eureka配置節點與全部eureka client基本相同再也不重述。

都改造完成後,信次前後啓動運行:服務配置中心(config server)【能夠運多個實例以不一樣的端口號】、服務消費客戶端(config client),發現一切都正常,當服務配置中心(config server)某個實例斷開仍不影響服務消費客戶端(config client),這樣就實現了高可用了。

好了,有關spring cloud config 總結就寫到這裏了,不少細節若需深究的話還有不少,後面項目中有實際用到再補充總結吧。文中如有不足,歡迎指出,碼字不易,請多支持,謝謝!  

分享可參考連接:

https://springcloud.cc/spring-cloud-config.html

https://blog.csdn.net/qq_20597727/article/details/82465069

 

提示:本文相關示例項目代碼均已上傳到GITHUB,地址以下:

https://github.com/zuowj/learning-demos/tree/master/java/demo-configserver

https://github.com/zuowj/learning-demos/tree/master/java/demo-configclient

相關文章
相關標籤/搜索