Spring Cloud 引導配置

1.概述

Spring Cloud是用於構建健壯的雲應用程序的框架。該框架通過為移動到分佈式環境時面臨的許多常見問題提供解決方案,從而促進了應用程序的開發。

使用微服務架構運行的應用程序旨在簡化開發,部署和維護。應用程序的分解特性使開發人員可以一次專注於一個問題。可以引入改進而不會影響系統的其他部分。

另一方面,當我們採用微服務方法時,會遇到不同的挑戰:

  • 外部化配置,以便靈活並且不需要在更改時重新構建服務
  • 服務發現
  • 隱藏部署在不同主機上的服務的複雜性

在本文中,我們將構建五個微服務:配置服務器,發現服務器,網關服務器,圖書服務以及最終的評級服務。這五個微服務形成了堅實的基礎應用程序,可以開始雲開發並解決上述挑戰。

2.配置服務器

開發雲應用程序時,一個問題是維護配置並將其分配給我們的服務。我們真的不想花時間配置每個環境,然後再水平擴展我們的服務,也不要通過將配置烘焙到應用程序中而冒著違反安全性的風險。

為了解決這個問題,我們將所有配置整合到一個Git存儲庫中,並將其連接到一個管理所有應用程序配置的應用程序。我們將要建立一個非常簡單的實現。

要了解更多細節並查看更複雜的示例,請查看我們的Spring Cloud Configuration文章。

2.1。設定

導航到[https://start.spring.io](https://start.spring.io)並選擇Maven和Spring Boot2.2.x。

將工件設置為“ config 。在依存關係部分中,搜索“配置服務器”並添加該模塊。然後按下“ generate按鈕,我們將能夠下載一個包含預先配置的項目的zip文件,並且可以開始使用。

另外,我們可以生成一個Spring Boot項目並手動將一些依賴項添加到POM文件中。

這些依賴關係將在所有項目之間共享:

<parent>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-parent</artifactId>

 <version>2.2.6.RELEASE</version>

 <relativePath/>

 </parent>



 <dependencies>

 <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>Hoxton.SR4</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>

讓我們為配置服務器添加一個依賴項:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-config-server</artifactId>

 </dependency>

作為參考,我們可以在Maven Central上找到最新版本( [spring-cloud-dependencies](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-dependencies%22) , [test](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.boot%22%20AND%20a%3A%22spring-boot-starter-test%22) , [config-server](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-config-server%22) )。

2.2。彈簧配置

要啟用配置服務器,我們必須在主應用程序類中添加一些註釋:

@SpringBootApplication

 @EnableConfigServer

 public class ConfigApplication {...}

@EnableConfigServer會將我們的應用程序轉換為配置服務器。

2.3 Properties

讓我們在src/main/resources添加application.properties

server.port=8081

 spring.application.name=config



 spring.cloud.config.server.git.uri=file://${user.home}/application-config

配置服務器最重要的設置是git.uri參數。當前,它設置為相對文件路徑,在Windows上通常解析為c:\Users\{username}\ ,在* nix上通常解析為/Users/{username}/ 。該屬性指向一個Git存儲庫,所有其他應用程序的屬性文件都存儲在該存儲庫中。如有必要,可以將其設置為絕對文件路徑。

提示:在Windows機器上,在* nix上以“ file:///”開頭,然後使用“ file://”。

2.4。 Git存儲庫

導航到spring.cloud.config.server.git.uri定義的文件夾,然後添加文件夾application-config 。將CD放入該文件夾,然後鍵入git init 。這將初始化一個Git存儲庫,我們可以在其中存儲文件並跟踪它們的更改。

2.5。運行程序

讓我們運行配置服務器並確保其正常工作。在命令行中輸入mvn spring-boot:run 。這將啟動服務器。

我們應該看到以下輸出指示服務器正在運行:

Tomcat started on port(s): 8081 (http)

2.6。引導配置

在後續的服務器中,我們將希望其應用程序屬性由此配置服務器管理。為此,我們實際上需要做一些簡單的事情:在每個應用程序中配置知道如何與該服務器對話的屬性。

這是一個引導過程,每個應用程序都會有一個名為bootstrap.properties的文件。它將包含與application.properties一樣的屬性,但有所不同:

父級Spring ApplicationContext首先加載bootstrap.properties這很關鍵,因此Config Server可以開始管理application.properties的屬性。正是這種特殊的ApplicationContext還將解密任何加密的應用程序屬性。

保留這些屬性文件的區別是很聰明的。 bootstrap.properties用於準備配置服務器,而application.properties用於特定於我們應用程序的屬性。但是從技術上講,可以將應用程序屬性放在bootstrap.properties

最後,由於Config Server正在管理我們的應用程序屬性,所以您可能會想知道為什麼根本沒有application.properties ?答案是,這些仍然可以作為Config Server可能沒有的默認值使用。

3.發現服務

現在,我們已經完成了配置工作,我們需要一種使所有服務器能夠相互查找的方法。我們將通過設置Eureka發現服務器來解決此問題。由於我們的應用程序可以在任何ip /端口組合上運行,因此我們需要一個中央地址註冊表,可以用作應用程序地址查找。

設置新服務器後,它將與發現服務器通信並註冊其地址,以便其他人可以與它通信。這樣,其他應用程序可以在發出請求時使用此信息。

要了解更多細節並查看更複雜的發現實現,請參閱Spring Cloud Eureka文章。

3.1。設定

再次,我們將導航到start.spring.io 。將工件設置為“發現”。搜索“ eureka服務器”並添加該依賴性。搜索“配置客戶端”並添加該依賴性。最後,生成項目。

另外,我們可以創建一個Spring Boot項目,從配置服務器複製POM的內容並交換以下依賴項:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-config</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-eureka-server</artifactId>

 </dependency>

作為參考,我們將在Maven Central( [config-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-config%22) , [eureka-server](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-eureka-server%22) )上找到這些捆綁包。

3.2 Spring配置

讓我們將Java配置添加到主類:

@SpringBootApplication

 @EnableEurekaServer

 public class DiscoveryApplication {...}

@EnableEurekaServer將使用Netflix Eureka將此服務器配置為發現服務器。 Spring Boot將自動檢測對類路徑的配置依賴關係,並從配置服務器中查找配置。

3.3 Properties

現在,我們將添加兩個屬性文件:

首先,我們將bootstrap.properties添加到src/main/resources

spring.cloud.config.name=discovery

 spring.cloud.config.uri=http://localhost:8081

這些屬性將使發現服務器在啟動時查詢配置服務器。

其次,我們將discovery.properties添加到我們的Git存儲庫中

spring.application.name=discovery

 server.port=8082



 eureka.instance.hostname=localhost



 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

 eureka.client.register-with-eureka=false

 eureka.client.fetch-registry=false

文件名必須與spring.application.name屬性匹配。

另外,我們告訴該服務器它正在默認區域中運行,這與配置客戶端的區域設置相匹配。我們還告訴服務器不要向另一個發現實例註冊。

在生產中,如果發生故障,我們將有多個提供冗餘,並且設置為真。

讓我們將文件提交到Git存儲庫。否則,將不會檢測到該文件。

3.4。將依賴性添加到配置服務器

將此依賴項添加到配置服務器POM文件中:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-eureka</artifactId>

 </dependency>

作為參考,我們可以在Maven Central( eureka-client )上找到該捆綁包。

將這些屬性添加到配置服務器的src/main/resources中的application.properties文件中:

eureka.client.region = default

 eureka.client.registryFetchIntervalSeconds = 5

 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

3.5。運行服務

使用相同的命令mvn spring-boot:run啟動發現服務器。命令行的輸出應包括:

Fetching config from server at: http://localhost:8081

 ...

 Tomcat started on port(s): 8082 (http)

停止並重新運行配置服務。如果一切順利,輸出應如下所示:

DiscoveryClient_CONFIG/10.1.10.235:config:8081: registering service...

 Tomcat started on port(s): 8081 (http)

 DiscoveryClient_CONFIG/10.1.10.235:config:8081 - registration status: 204

4. Gateway

現在,我們已經解決了配置和發現問題,客戶端訪問我們所有的應用程序仍然遇到問題。

如果我們將所有內容保留在分佈式系統中,那麼我們將必須管理複雜的CORS標頭,以允許在客戶端上進行跨域請求。我們可以通過創建網關服務器來解決此問題。這將充當從客戶端到我們的後端服務器的反向代理穿梭請求。

網關服務器是微服務體系結構中的出色應用程序,因為它允許所有響應都來自單個主機。這將消除對CORS的需求,並為我們提供了一個方便的地方來處理諸如身份驗證之類的常見問題。

4.1。設定

至此,我們知道了演習。導航到https://start.spring.io 。將工件設置為“ gateway”。搜索“ zuul”並添加該依賴性。搜索“配置客戶端”並添加該依賴性。搜索“ eureka發現”並添加該依賴性。最後,生成該項目。

或者,我們可以創建具有以下依賴項的Spring Boot應用程序:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-config</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-eureka</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-zuul</artifactId>

 </dependency>

作為參考,我們可以在Maven Central( [config-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-config%22) , [eureka-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-eureka%22) , [zuul](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-zuul%22) )上找到該捆綁包。

4.2。Spring Config

讓我們將配置添加到主類:

@SpringBootApplication

 @EnableZuulProxy

 @EnableEurekaClient

 public class GatewayApplication {...}

4.3。Properties

現在,我們將添加兩個屬性文件:

src/main/resources bootstrap.properties

spring.cloud.config.name=gateway

 spring.cloud.config.discovery.service-id=config

 spring.cloud.config.discovery.enabled=true



 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

我們的Git存儲庫中的gateway.properties

spring.application.name=gateway

 server.port=8080



 eureka.client.region = default

 eureka.client.registryFetchIntervalSeconds = 5



 zuul.routes.book-service.path=/book-service/**

 zuul.routes.book-service.sensitive-headers=Set-Cookie,Authorization

 hystrix.command.book-service.execution.isolation.thread.timeoutInMilliseconds=600000



 zuul.routes.rating-service.path=/rating-service/**

 zuul.routes.rating-service.sensitive-headers=Set-Cookie,Authorization

 hystrix.command.rating-service.execution.isolation.thread.timeoutInMilliseconds=600000



 zuul.routes.discovery.path=/discovery/**

 zuul.routes.discovery.sensitive-headers=Set-Cookie,Authorization

 zuul.routes.discovery.url=http://localhost:8082

 hystrix.command.discovery.execution.isolation.thread.timeoutInMilliseconds=600000

zuul.routes屬性允許我們定義一個應用程序,以基於螞蟻URL匹配器路由某些請求。我們的屬性告訴Zuul將/book-service/**中出現的任何請求路由到具有book-servicespring.application.name的應用程序。然後,Zuul將使用應用程序名稱從發現服務器中查找主機,並將請求轉發到該服務器。

記住要提交存儲庫中的更改!

4.4。運行應用程序

運行配置和發現應用程序,然後等待直到配置應用程序已在發現服務器中註冊。如果它們已經在運行,則不必重新啟動它們。完成後,運行網關服務器。網關服務器應在端口8080上啟動,並在發現服務器中註冊自己。控制台的輸出應包含:

Fetching config from server at: http://10.1.10.235:8081/

 ...

 DiscoveryClient_GATEWAY/10.1.10.235:gateway:8080: registering service...

 DiscoveryClient_GATEWAY/10.1.10.235:gateway:8080 - registration status: 204

 Tomcat started on port(s): 8080 (http)

容易犯的一個錯誤是在配置服務器向Eureka註冊之前啟動服務器。在這種情況下,我們將看到帶有以下輸出的日誌:

Fetching config from server at: http://localhost:8888

這是配置服務器的默認URL和端口,表示發出配置請求時我們的發現服務沒有地址。只需等待幾秒鐘,然後重試,一旦配置服務器在Eureka中註冊後,問題便會解決。

5.圖書服務

在微服務架構中,我們可以自由製作盡可能多的應用程序來實現業務目標。工程師通常會按領域劃分其服務。我們將遵循這種模式,並創建一個圖書服務來處理應用程序中圖書的所有操作。

5.1。設定

再一次。導航到[https://start.spring.io](https://start.spring.io/) 。將工件設置為“ book-service”。搜索“ web”並添加該依賴性。搜索“配置客戶端”並添加該依賴性。搜索“ eureka發現”並添加該依賴性。生成該項目。

或者,將這些依賴項添加到項目中:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-config</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-eureka</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

 </dependency>

作為參考,我們可以在Maven Central( [config-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-config%22) , [eureka-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-eureka%22) , [web](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.boot%22%20AND%20a%3A%22spring-boot-starter-web%22) )上找到該捆綁包。

5.2。Spring Config

讓我們修改主類:

@SpringBootApplication

 @EnableEurekaClient

 @RestController

 @RequestMapping("/books")

 public class BookServiceApplication {

 public static void main(String[] args) {

 SpringApplication.run(BookServiceApplication.class, args);

 }



 private List<Book> bookList = Arrays.asList(

 new Book(1L, "Baeldung goes to the market", "Tim Schimandle"),

 new Book(2L, "Baeldung goes to the park", "Slavisa")

 );



 @GetMapping("")

 public List<Book> findAllBooks() {

 return bookList;

 }



 @GetMapping("/{bookId}")

 public Book findBook(@PathVariable Long bookId) {

 return bookList.stream().filter(b -> b.getId().equals(bookId)).findFirst().orElse(null);

 }

 }

我們還添加了一個REST控制器和一個由屬性文件設置的字段,以返回我們將在配置期間設置的值。

現在添加書POJO:

public class Book {

 private Long id;

 private String author;

 private String title;



 // standard getters and setters

 }

5.3。Properties

現在,我們只需要添加兩個屬性文件:

src/main/resources bootstrap.properties

spring.cloud.config.name=book-service

 spring.cloud.config.discovery.service-id=config

 spring.cloud.config.discovery.enabled=true



 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

我們的Git存儲庫中的book-service.properties

spring.application.name=book-service

 server.port=8083



 eureka.client.region = default

 eureka.client.registryFetchIntervalSeconds = 5

 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

讓我們將更改提交到存儲庫。

5.4。啓動程序

一旦所有其他應用程序啟動,我們就可以啟動圖書服務。控制台輸出應如下所示:

DiscoveryClient_BOOK-SERVICE/10.1.10.235:book-service:8083: registering service...

 DiscoveryClient_BOOK-SERVICE/10.1.10.235:book-service:8083 - registration status: 204

 Tomcat started on port(s): 8083 (http)

一旦啟動,我們就可以使用瀏覽器訪問剛剛創建的端點。導航到http:// localhost:8080 / book-service / books,我們返回一個JSON對象,其中包含我們添加到out控制器中的兩本書。請注意,我們沒有直接在端口8083上訪問圖書服務,而是通過網關服務器。

6.評級服務

就像我們的圖書服務一樣,我們的評分服務將是域驅動的服務,它將處理與評分相關的操作。

6.1。設定

再一次。導航到https://start.spring.io 。將工件設置為“ rating-service”。搜索“ web”並添加該依賴性。搜索“配置客戶端”並添加該依賴性。搜索 eureka發現並添加該依賴性。然後,生成該項目。

或者,將這些依賴項添加到項目中:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-config</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-eureka</artifactId>

 </dependency>

 <dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

 </dependency>

作為參考,我們可以在Maven Central( [config-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-config%22) , [eureka-client](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.cloud%22%20AND%20a%3A%22spring-cloud-starter-eureka%22) , [web](https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.springframework.boot%22%20AND%20a%3A%22spring-boot-starter-web%22) )上找到該捆綁包。

6.2。Spring Config

讓我們修改主類:

@SpringBootApplication

 @EnableEurekaClient

 @RestController

 @RequestMapping("/ratings")

 public class RatingServiceApplication {

 public static void main(String[] args) {

 SpringApplication.run(RatingServiceApplication.class, args);

 }



 private List<Rating> ratingList = Arrays.asList(

 new Rating(1L, 1L, 2),

 new Rating(2L, 1L, 3),

 new Rating(3L, 2L, 4),

 new Rating(4L, 2L, 5)

 );



 @GetMapping("")

 public List<Rating> findRatingsByBookId(@RequestParam Long bookId) {

 return bookId == null || bookId.equals(0L) ? Collections.EMPTY_LIST : ratingList.stream().filter(r -> r.getBookId().equals(bookId)).collect(Collectors.toList());

 }



 @GetMapping("/all")

 public List<Rating> findAllRatings() {

 return ratingList;

 }

 }

我們還添加了一個REST控制器和一個由屬性文件設置的字段,以返回我們將在配置期間設置的值。

讓我們添加評級POJO:

public class Rating {

 private Long id;

 private Long bookId;

 private int stars;



 //standard getters and setters

 }

6.3 Properties

現在,我們只需要添加兩個屬性文件:

src/main/resources bootstrap.properties

spring.cloud.config.name=rating-service

 spring.cloud.config.discovery.service-id=config

 spring.cloud.config.discovery.enabled=true



 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

我們的Git存儲庫中的rating-service.properties

spring.application.name=rating-service

 server.port=8084



 eureka.client.region = default

 eureka.client.registryFetchIntervalSeconds = 5

 eureka.client.serviceUrl.defaultZone=http://localhost:8082/eureka/

讓我們將更改提交到存儲庫。

6.4 運行程序

一旦所有其他應用程序啟動,我們就可以啟動評級服務。控制台輸出應如下所示:

DiscoveryClient_RATING-SERVICE/10.1.10.235:rating-service:8083: registering service...

 DiscoveryClient_RATING-SERVICE/10.1.10.235:rating-service:8083 - registration status: 204

 Tomcat started on port(s): 8084 (http)

一旦啟動,我們就可以使用瀏覽器訪問剛剛創建的端點。導航到http://localhost:8080/rating-service/ratings/all ,我們返回包含所有評分的JSON。請注意,我們沒有直接在端口8084上訪問分級服務,而是通過網關服務器。

7.結論

現在,我們能夠將Spring Cloud的各個部分連接到一個正常運行的微服務應用程序中。這構成了我們可以用來開始構建更複雜的應用程序的基礎。

與往常一樣,我們可以在GitHub上找到此源代碼。