spring cloud-config配置中心


  Spring Cloud Config為分布式系統中的外部化配置提供了服務器端和客戶端支持。有了配置服務器,您就有了一個中心位置來管理跨所有環境的應用程序的外部屬性。本文記錄實現一個配置中心、客戶端獲取配置參數、refresh手動刷新。

官方文檔:https://cloud.spring.io/spring-cloud-config/single/spring-cloud-config.html

  幫助文檔:https://spring.io/guides/gs/centralized-configuration/

 

Config Server

  首先我們基於之前的代碼,在springCloud工程下面新建一個Config Server,是一個springboot項目,並且在Eureka上面注冊服務(還不會服務注冊與發現的,請戳:SpringCloud系列——Eureka 服務注冊與發現),本例使用的是GitHub

  maven引jar

        <!-- config-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>

  登錄GitHub,新建一個public倉庫:config-server,並且添加測試項目對應的配置文件:myspringboot-dev.properties,並設置幾個值

  配置文件

server.port=1112
spring.application.name=config-server

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
#健康檢查(需要spring-boot-starter-actuator依賴)
eureka.client.healthcheck.enabled=true
# 續約更新時間間隔(默認30秒)
eureka.instance.lease-renewal-interval-in-seconds=10
# 續約到期時間(默認90秒)
eureka.instance.lease-expiration-duration-in-seconds=10

#連接GitHub
spring.cloud.config.server.git.uri=https://github.com/huanzi-qch/config-server.git
spring.cloud.config.server.git.search-paths=config-server
spring.cloud.config.label=master
spring.cloud.config.server.git.username=******
spring.cloud.config.server.git.password=******

啟動類加入注解@EnableConfigServer

@EnableConfigServer
@EnableEurekaClient
@SpringBootApplication
public class ConfigServerApplication {

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

 啟動項目,訪問http://localhost:1112/myspringboot-dev.properties/,發現有中文亂碼

  注:倉庫中的配置文件會被轉換成web接口,訪問規則:

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

  解決中文亂碼,參考:https://blog.csdn.net/sinat_38843093/article/details/79960777

  新建自定義解析器MyPropertiesHandler,繼承PropertiesPropertySourceLoader,重寫方法

/**
 * 解決中文亂碼問題
 * 參考:https://blog.csdn.net/sinat_38843093/article/details/79960777
 */
public class MyPropertiesHandler extends PropertiesPropertySourceLoader {

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

    @Override
    public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
        ArrayList<PropertySource<?>> list = new ArrayList<>();
        Properties properties = getProperties(resource);
        if (!properties.isEmpty()) {
            list.add(new PropertiesPropertySource(name, properties));
        }
        return list;
    }

    private Properties getProperties(Resource resource) throws IOException {
        Properties properties = new Properties();
        InputStream inputStream = resource.getInputStream();
        properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        inputStream.close();
        return properties;
    }
}

resources文件夾下面新建META-INF文件夾,在里面創建spring.factories文件,指定使用我們自定義的解析器

org.springframework.boot.env.PropertySourceLoader=cn.huanzi.qch.config.configserver.MyPropertiesHandler

重新啟動項目,在自定義解析器后進行斷點調試,發現解析的時候中文亂碼問題得以解決,但響應回去還是亂碼

  解決http響應中文亂碼問題

  配置文件添加

#解決http響應數據中文亂碼問題
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8

 最終效果

   我們去GitHub修改配置中心的值,看下config server能不能實時獲取最新數據

  改完后刷新http://localhost:1112/myspringboot-dev.properties/,配置中心可以實時獲取最新數據

 

 

  Config Client

  客戶端我們直接用之前的項目:myspringboot,這里就當做一個在Eureka上注冊了的普通springboot項目

  maven引入jar

        <!-- config-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>

  application.properties

#設置服務端口
server.port=10087
spring.application.name=myspringboot

#eureka
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
#健康檢查(需要spring-boot-starter-actuator依賴)
eureka.client.healthcheck.enabled=true
# 續約更新時間間隔(默認30秒)
eureka.instance.lease-renewal-interval-in-seconds=10
# 續約到期時間(默認90秒)
eureka.instance.lease-expiration-duration-in-seconds=10
#超時時間
feign.httpclient.connection-timeout=30000

使用優先級更高的bootstrap.properties進行config的配置,因為

#關閉spring cloud config,spring cloud默認要從config中讀取配置,通過該配置,只從本地application.properties中讀取配置
#spring.cloud.config.enabled=false

#配置文件名(當應用名跟配置文件相同時可以不用配置)
spring.cloud.config.name=myspringboot
# dev 開發環境配置文件 |  test 測試環境  |  pro 正式環境
spring.cloud.config.profile=dev
# 遠程倉庫的分支
spring.cloud.config.label=master

#指定配置中心名稱(如果使用eureka可以這樣配置)
#spring.cloud.config.discovery.service-id=config-server
#啟用發現服務功能
#spring.cloud.config.discovery.enabled=true

#配置服務中心地址(如果不使用eureka可以直接配置url路徑)
spring.cloud.config.uri=http://localhost:1112/

如果使用從eureka獲取配置中心實例,則要在指定服務之前進行注冊配置,否則會報錯,因為你還沒在Eureka注冊就去Eureka查找配置中心,如:

#設置服務端口
server.port=10087
spring.application.name=myspringboot

#eureka
eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/
#健康檢查(需要spring-boot-starter-actuator依賴)
eureka.client.healthcheck.enabled=true
# 續約更新時間間隔(默認30秒)
eureka.instance.lease-renewal-interval-in-seconds=10
# 續約到期時間(默認90秒)
eureka.instance.lease-expiration-duration-in-seconds=10
#超時時間
feign.httpclient.connection-timeout=30000

#關閉spring cloud config,spring cloud默認要從config中讀取配置,通過該配置,只從本地application.properties中讀取配置
#spring.cloud.config.enabled=false

#配置文件名(當應用名跟配置文件相同時可以不用配置)
spring.cloud.config.name=myspringboot
# dev 開發環境配置文件 |  test 測試環境  |  pro 正式環境
spring.cloud.config.profile=dev
# 遠程倉庫的分支
spring.cloud.config.label=master

#指定配置中心名稱(如果使用eureka可以這樣配置)
spring.cloud.config.discovery.service-id=config-server
#啟用發現服務功能
spring.cloud.config.discovery.enabled=true

#配置服務中心地址(如果不使用eureka可以直接配置url路徑)
#spring.cloud.config.uri=http://localhost:1112/

 

測試

  我們直接在啟動類進行測試

@EnableEurekaClient
@SpringBootApplication
@RestController
public class MyspringbootApplication{

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

    @Value("${huanzi.qch.config.server.username}")
    private String username;

    /**
     * 訪問首頁
     */
    @GetMapping("/index")
    public String index(){
        return "hello springboot!username:" + username;
    }

}

查看啟動日志,客戶端已經發現了配置中心,並且從配置中心發現了myspringboot配置文件

  訪問http://localhost:10087/index,值已經取到了

 

  其實客戶端(Config Client)也是可以讀取服務端(Config Server)配置文件里面的值,例如:

  客戶端(Config Client)是可以讀取到這個值的,由此可見,是客戶端是讀取了服務端的數據,而服務端負責實時獲取GitHub上面的數據

 

  refresh手動刷新

  我們已經在客戶端取到了配置中心的值,但當我們修改GitHub上面的值時,服務端(Config Server)能實時獲取最新的值,但客戶端(Config Client)讀的是緩存,無法實時獲取最新值

  spring已經為我們解決了這個問題,那就是客戶端使用post去觸發refresh,獲取最新數據,需要依賴spring-boot-starter-actuator

 <!-- actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

對應的controller類加上@RefreshScope

@RefreshScope
@EnableEurekaClient
@SpringBootApplication
@RestController
public class MyspringbootApplication{

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

    @Value("${huanzi.qch.config.server.username}")
    private String username;

    /**
     * 訪問首頁
     */
    @GetMapping("/index")
    public String index(){
        return "hello springboot!username:" + username;
    }

}

啟動后查看日志發現,actuator有個基礎路徑/actuator,同時還暴露了兩個終端(不知道是哪兩個端點...)

  但是當我們post訪問http://localhost:10087/actuator/refresh時,報404,這是什么回事?

  注:這里插一句話:從網上找了個js的ajax(要注意content-type的類型)

復制代碼
var Ajax={
  get: function(url, fn) {
    // XMLHttpRequest對象用於在后台與服務器交換數據
    var xhr = new XMLHttpRequest();            
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function() {
      // readyState == 4說明請求已完成
      if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { 
        // 從服務器獲得數據
        fn.call(this, xhr.responseText);  
      }
    };
    xhr.send();
  },
  // datat應為'a=a1&b=b1'這種字符串格式,在jq里如果data為對象會自動將對象轉成這種字符串格式
  post: function (url, data, fn) {
    var xhr = new XMLHttpRequest();
    xhr.open("POST", url, true);
    // 添加http頭,發送信息至服務器時內容編碼類型
    xhr.setRequestHeader("Content-Type", "application/json");  
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) {
        fn.call(this, xhr.responseText);
      }
    };
    xhr.send(data);
  }
}
復制代碼
Ajax.post("http://localhost:10087/actuator/refresh",null,function(data){console.log(data)})

  經過層層查找,最后在幫助文檔發現:默認情況下,自Spring Boot 2.0以來,默認情況下不會公開Actuator端點,需要手動暴露端點

  配置文件暴露端點

#只暴露refresh,當然也可以暴露所有:=*
management.endpoints.web.exposure.include=refresh

  重啟客戶端,我們將GitHub配置文件改回:huanzi.qch.config.server.username: 張三

  訪問測試接口,還是張三1

  post調用refresh

  刷新,數據更新

 

  總結

  這里總結一下遇到的坑:

  調用refresh報404的時候,百度查找都是說默認安全攔截,配置關閉:management.security.enabled=false,配置上去的時候發現報錯,波浪線,被棄用了,

  最后還是靠Google,在知乎(https://zhuanlan.zhihu.com/p/34784934)上面找到了答案

 

  

  並且吐槽吐槽百度:

  同樣的關鍵字,Google搜出來的第一個就能解決問題 

  而垃圾百度,沒一個可以...

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM