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)

??統(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é)果

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

注意圖中寫的不再是bus-refresh而是使用的monitor,這里是一個細節(jié)要注意一下。
好的,SpringCloud配置中心就講到這里,歡迎大家指正