SpringCloud之spring-cloud-config-server

1.為什么需要統(tǒng)一配置中心

1.1方便維護

??在項目開發(fā)中,大家肯定都會對同一個配置文件做修改,有時候A希望使用這個配置開發(fā),B希望臨時更改一個配置然后在測試一下,等等然后配置文件就該亂了,導致配置非常難維護

1.2配置內(nèi)容安全與權(quán)限

??在大公司里面,我們從來都不會在配置文件中看到數(shù)據(jù)庫的密碼以及其他一些敏感的配置信息,所以把關(guān)鍵的配置信息隔離出來是非常有必要的

1.3更新項目配置需要重啟

??這個就不多說了~

2.統(tǒng)一配置中心架構(gòu)

架構(gòu)圖

??統(tǒng)一配置中心有一個config-server端,它會從遠端的git拉取配置,并且同步到本地git中,所以即使遠端git掛掉了,本地git依然能夠提供支持。右邊的product和order兩個微服務(wù)是統(tǒng)一配置的客戶端,可以從config-server獲取配置。

3.configServer端配置

3.1依賴

??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>

    <groupId>com.imooc</groupId>
    <artifactId>config</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>config</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-monitor</artifactId>
        </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>

</project>

3.2注解

??main函數(shù)上面加注解,注意,即是eureka的客戶端,同時又是config的server端

@SpringBootApplication
@EnableDiscoveryClient
@EnableConfigServer
public class ConfigApplication {

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

3.3配置

??在application.yml中加相應(yīng)的配置

spring:
  application:
    name: config
  cloud:
    config:
      server:
        git:
          uri: https://gitlab-demo.com/SpringCloud_Sell/config-repo.git
          username: mikezzmeric
          password: 嘿嘿嘿嘿
          basedir: /Users/admin/code/myProjects/java/imooc/SpringCloud_Sell/config/basedir
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:8761/eureka/,http://eureka2:8762/eureka/
management:
  endpoints:
    web:
      expose: "*"

上面的配置文件中配置了git地址,這樣我們可以從git上獲取配置文件
同時也把自己注冊到eureka上,作為一個微服務(wù)
baseDir是什么意思呢,因為統(tǒng)一配置中心是要把配置文件從服務(wù)器上放到本地存儲一份,這個baseDir就是存儲配置文件的路徑

3.4啟動應(yīng)用

??訪問http://localhost:8080/order-a.yml或者http://localhost:8080/order-b.yml我們發(fā)現(xiàn)都有輸出而且與git上的配置文件一模一樣,但是如果訪問http://localhost:8080/order.yml就會什么都看不到



??為什么會這樣?!我們可以看一下ConfigServer時候,控制臺輸出的信息如下圖:



??通過控制臺我們可以看到很多訪問配置文件的形式和格式。這里我們換成properties去訪問這個路徑會發(fā)現(xiàn)和之前通過yml的形式去訪問又不一樣了



??假設(shè)我們故意寫錯配置文件,然后再次通過yml的形式去訪問,我們再來看一下結(jié)果:

??其實這里有兩種常用的配置文件規(guī)則(個人傾向于用/{name}-{profiles}.yml文件):



??為了理解這兩種常用的配置文件規(guī)則,我們在git上在創(chuàng)建一個order-dev.yml的配置文件,相比于剛才的order.yml多出一個配置項,如下圖所示,以表示區(qū)分:

??我們訪問一下order-dev這個配置文件:

??特別注意一下,在瀏覽器這里我輸入的是order-dev這個文件是在遠程倉庫中有的文件名,而剛才我輸入order.yml卻報錯了,一定要注意這個細節(jié),我后面會講為什么會這樣!接下來我們在git上再創(chuàng)建一個分支release,并且將release分支的order-dev.yml做一點修改:

??接下來我們按照label的形式來訪問一下配置文件,也可以訪問到對應(yīng)的文件:

??到這里為止,我還是沒有給大家解答為什么order.yml不能訪問,但是order-a.yml能訪問的問題,這里先賣個關(guān)子,大家先回憶一下在教程開篇的時候我們提到過,config-server會把配置文件從git端放到本地,那么我們訪問到的配置文件究竟放到哪里了呢?我們可以看一下控制臺的日志:



我們在線上的時候,不可能有這么一個隨意的路徑,那怎么更改這個路徑呢:

4.configServer Client端

??好了3中的遺留問題我們就放在這里給大家解答,在此之前我們看一下Client是如何搭建的。

4.1pom.xml

??引入config-client的客戶端即可

4.2bootstrap.yml

??很奇怪為什么不再是application.yml了,而是bootstrap.yml了,首先這里的bootstrap不是前端的bootstrap,之所以使用bootstrap.yml是因為我們現(xiàn)在要從配置中心去獲取數(shù)據(jù)庫的配置,如果使用application.yml這個配置文件去配置中心獲取配置,我們會發(fā)現(xiàn)數(shù)據(jù)庫無法正常連接,因為springboot不知道是從config-server拿配置在前還是先連接數(shù)據(jù)庫在前,所以我們使用bootstrap.yml這個文件可以解決這個問題。

spring:
  application:
    name: order
  cloud:
    config:
      discovery:
        enabled: true
        service-id: CONFIG
      profile: test
eureka:
  client:
    service-url:
      defaultZone: http://eureka1:8761/eureka/,http://eureka2:8762/eureka/
  instance:
    prefer-ip-address: true

service-id:CONFIG表示配置中心的ID,profile表示要獲取的是哪一個配置文件。
啟動客戶端應(yīng)用的時候,我們的client端會去訪問eureka,通過eureka拿到config服務(wù)所在的地址,然后在通過這個服務(wù)地址去獲取配置文件。這里我們回答一下3中留下的問題,我們可以在訪問order-test.yml的時候,通過截圖我們可以看到訪問了兩個配置文件,order.yml和order-test.yml,兩個配置文件訪問后,會做合并返回給客戶端,這就是為什么即使我們輸入不存在的order-a.yml也能正確返回文件的原因。所以我們會把公共的配置放在order.yml中!


5.SpringCloudBus自動刷新配置


我們之前講的ConfigServer還不能做到配置更新后不重啟服務(wù)器,要做到不重啟,我們需要借助SpringCloudBus這個東西。我們可以回想一下,為什么之前我們做不到配置實時更新呢?原因就是配置更新后,沒有將更新通知到對應(yīng)的服務(wù)。所以我們這里需要借助一個消息隊列,當發(fā)生更新后,讓消息隊列來通知各個服務(wù)。configServer引入了Bus之后,會提供一個bus-refresh的http接口,通過這個接口可以告訴config-server配置更新了,從圖里面我們可以看出git可以在更新后訪問這個接口來告訴config-server。

5.1ConfigServer端配置

5.1.1pom.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>

    <groupId>com.imooc</groupId>
    <artifactId>config</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>config</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-monitor</artifactId>
        </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>

</project>

5.1.2application.yml配置

spring:
  application:
    name: config
  cloud:
    config:
      server:
        git:
          uri: https://github.com/mikezzmeric/config-repo.git
          username: mikezzmeric
          password: 嘿嘿
          basedir: F:/SpringCloud/config/basedir
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
management:
  endpoints:
    web:
      expose: "*"

這里要把management配置出來,否則bus-refresh接口暴露不出來

5.2Order端配置

5.2.1pom.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.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.configclient</groupId>
    <artifactId>order</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>order</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </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>
</project>

5.2.2Config

package com.configclient.order.com.configclient.order.controller.zzmconfig;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@Data
@Component
@ConfigurationProperties(prefix = "girl")
@RefreshScope
public class ZZMConfig {

    private String name;

    private Integer age;
}

一定要加上RegreshScope,否則完全即使修改了文件內(nèi)容,也不會更新配置

5.2.3Controller

package com.configclient.order.com.configclient.order.controller;

import com.configclient.order.com.configclient.order.controller.zzmconfig.ZZMConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ZZMController {
    @Autowired
    private ZZMConfig zzmConfig;

    @GetMapping("/zzm/print")
    public String print(){
        return "name:" +zzmConfig.getName()+",age:"+zzmConfig.getAge();
    }
}

5.2.4更新配置

當在git上修改對應(yīng)的配置文件后,發(fā)起post請求


5.2.5查看結(jié)果

image.png

??這樣可以不啟停應(yīng)用,配置也更新了,但是我們發(fā)現(xiàn),每次更新完成后,都必須要發(fā)起一個post請求,能否有辦法自動觸發(fā)這個更新呢?答案是在github上配置一個webhooks,可以參考下圖:



注意圖中寫的不再是bus-refresh而是使用的monitor,這里是一個細節(jié)要注意一下。

好的,SpringCloud配置中心就講到這里,歡迎大家指正

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容