1. 概述
Spring Cloud Consul 項目提供與 Spring Boot 應用程序的便捷集成,利用 Consul。
Consul 是一個提供用於解決微服務架構中一些常見挑戰的組件的工具:
- 服務發現 – 自動註冊和註銷服務實例的網絡位置
- 健康檢查 – 檢測服務實例是否處於運行狀態
- 分佈式配置 – 確保所有服務實例使用相同的配置
在本文中,我們將瞭解如何配置 Spring Boot 應用程序以使用這些功能。
2. 先決條件
首先,建議您快速瞭解 Consul及其所有功能。
在本文中,我們將使用運行在 localhost:8500 的 Consul 代理。有關如何安裝 Consul 並運行代理的更多詳細信息,請參閲此 鏈接。
首先,我們需要將 spring-cloud-starter-consul-all 依賴項添加到我們的 pom.xml 中:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
<version>3.1.1</version>
</dependency>3. 服務發現
讓我們編寫我們的第一個 Spring Boot 應用程序,並與正在運行的 Consul 代理進行集成:
@SpringBootApplication
public class ServiceDiscoveryApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(ServiceDiscoveryApplication.class)
.web(true).run(args);
}
}默認情況下,Spring Boot 會嘗試連接到 Consul 代理,地址為 localhost:8500. 要使用其他設置,需要更新 application.yml 文件:
spring:
cloud:
consul:
host: localhost
port: 8500然後,如果我們在瀏覽器中訪問 Consul 代理的站點,地址為 http://localhost:8500,我們會看到我們的應用程序已正確地在 Consul 中註冊,標識符來自 “${spring.application.name}:${profiles separated by comma}:${server.port}”。
為了自定義此標識符,我們需要更新屬性 spring.cloud.discovery.instanceId 為另一個表達式:
spring:
application:
name: myApp
cloud:
consul:
discovery:
instanceId: ${spring.application.name}:${random.value}如果再次運行該應用程序,我們會發現它使用了“MyApp”標識符加上一個隨機值進行註冊。我們需要這樣做,以便在本地機器上運行該應用程序的多個實例。
最後,要禁用服務發現,需要將 spring.cloud.consul.discovery.enabled 屬性設置為 false。
3.1. 查詢服務
我們已經在 Consul 中註冊了我們的應用程序,但客户端如何找到服務端點?我們需要一個發現客户端服務,從 Consul 獲取正在運行且可用的服務。
Spring 提供 DiscoveryClient API 用於此目的,我們可以通過使用 @EnableDiscoveryClient 註解啓用它:
@SpringBootApplication
@EnableDiscoveryClient
public class DiscoveryClientApplication {
// ...
}然後,我們可以將 DiscoveryClient Bean 注入到我們的控制器中,並訪問其實例:
@RestController
public class DiscoveryClientController {
@Autowired
private DiscoveryClient discoveryClient;
public Optional<URI> serviceUrl() {
return discoveryClient.getInstances("myApp")
.stream()
.findFirst()
.map(si -> si.getUri());
}
}最後,我們將定義應用程序的端點:
@GetMapping("/discoveryClient")
public String discoveryPing() throws RestClientException,
ServiceUnavailableException {
URI service = serviceUrl()
.map(s -> s.resolve("/ping"))
.orElseThrow(ServiceUnavailableException::new);
return restTemplate.getForEntity(service, String.class)
.getBody();
}
@GetMapping("/ping")
public String ping() {
return "pong";
}“myApp/ping”路徑是Spring應用程序名稱,包含服務端點。Consul將提供所有名為myApp的應用程序。
4. 健康檢查
Consul 定期檢查服務端點的健康狀況。
默認情況下,Spring 實現健康端點,如果應用程序正常運行,則返回 200 OK。 如果需要自定義端點,則必須更新 application.yml。
spring:
cloud:
consul:
discovery:
healthCheckPath: /my-health-check
healthCheckInterval: 20s因此,Consul 將每 20 秒對 “/my-health-check” 端點進行輪詢。
讓我們定義我們的自定義健康檢查服務,以返回 FORBIDDEN 狀態:
@GetMapping("/my-health-check")
public ResponseEntity<String> myCustomCheck() {
String message = "Testing my healh check function";
return new ResponseEntity<>(message, HttpStatus.FORBIDDEN);
}如果我們訪問 Consul 代理站點,我們會發現我們的應用程序正在失敗。為了解決這個問題,“/my-health-check” 服務應該返回 HTTP 200 OK 狀態碼。
5. 分佈式配置
此功能允許在所有服務之間同步配置。
Consul 會監視任何配置更改,然後觸發所有服務的更新。
首先,我們需要在我們的 pom.xml 中添加 spring-cloud-starter-consul-config 依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
<version>3.1.1</version>
</dependency>我們還需要將 Consul 和 Spring 應用名稱的設置從 application.yml 文件移動到 bootstrap.yml 文件中,因為 Spring 會首先加載 bootstrap.yml 文件。
然後,我們需要啓用 Spring Cloud Consul Config:
spring:
application:
name: myApp
cloud:
consul:
host: localhost
port: 8500
config:
enabled: trueSpring Cloud Consul Config 將在 Consul 中查找屬性,路徑為 “/config/myApp”。如果有一個名為 “my.prop” 的屬性,則需要在 Consul 代理站點創建該屬性。
可以通過前往 “KEY/VALUE” 部分,然後輸入 “/config/myApp/my/prop” 到 “Create Key” 表單中,以及 “Hello World” 作為值,即可創建屬性。最後,點擊 “Create” 按鈕。
請注意,如果我們在使用 Spring 配置文件,則需要將配置文件名稱附加到 Spring 應用名稱後。例如,如果我們在使用 “dev” 配置文件,則 Consul 路徑最終將為 “/config/myApp,dev”。
現在,讓我們看看包含注入屬性的控制器是什麼樣子的:
@RestController
public class DistributedPropertiesController {
@Value("${my.prop}")
String value;
@Autowired
private MyProperties properties;
@GetMapping("/getConfigFromValue")
public String getConfigFromValue() {
return value;
}
@GetMapping("/getConfigFromProperty")
public String getConfigFromProperty() {
return properties.getProp();
}
}以及 MyProperties 類:
@RefreshScope
@Configuration
@ConfigurationProperties("my")
public class MyProperties {
private String prop;
// standard getter, setter
}如果運行該應用程序,字段 value 和 properties 均具有與 Consul 相同的 值。
5.1. 更新配置
如果沒有重啓 Spring Boot 應用程序,如何更新配置呢?
如果返回到 Consul 代理站點,並更新屬性“/config/myApp/my/prop”為另一個值,例如“New Hello World”,則字段“value”不會發生變化,字段“properties”將被更新為“New Hello World”,正如預期的那樣。
這是因為字段“properties”是一個 MyProperties 類,具有 @RefreshScope 註解。所有帶有 @RefreshScope 註解的 Bean 在配置更改後都會被刷新。
在實際應用中,我們不應該在 Consul 中直接存儲屬性,而是應該將它們持久地存儲在其他地方。我們可以使用 Config Server 來實現這一點。
6. 結論
在本文中,我們學習瞭如何配置 Spring Boot 應用程序,以便與 Consul 進行服務發現,自定義健康檢查規則並共享分佈式配置。
我們還介紹了客户端調用這些註冊服務的一系列方法。