使用Spring Boot的消費者驅動合同
在本文中,我們將討論消費者驅動開發的細節。
#問題
主要問題是基於API介面上的消費者和生產者之間的衝突,當開發任何api時,你應該考慮的是你的客戶的舒適度。如果你所做的更改打破了客戶端的體驗,那完全是一個笑話,本文討論了消費者和生產者服務之間這種協議挑戰。
#解決之道
消費者驅動合同(CDC)是確保生產者和消費者之間、分散式系統或微服務中基於HTTP或基於訊息或基於事件的軟體之間的執行正確的協議合約或合同。
Spring Cloud Contract是基於JVM的語言的CDC開發的實現,它也支援非基於jvm的語言,它將TDD提升到軟體(api)設計和架構的水平,我稱之為CDC - > Client Driven Development,因為是客戶端(消費者)驅動生產者API的變化。
#為什麼?
有關上面提到的一些問題和解決方案,你可能想為什麼我們需要這種方法?消費者和生產者之間的握手在微服務架構設計存在一些挑戰,因為,生產者所做的改變很難在消費者方面進行測試。見下面這個微服務圖片:
當試圖測試與許多其他服務進行通訊的應用程式時,我們可以在沒有消費者驅動合同的情況下做以下事情:
1. 部署所有微服務並執行端到端測試。
2. 在測試中模擬Mock其他服務。
兩種方法都有其優點和缺點。
部署所有微服務;
優點 - >模擬生產,測試實際服務,更可靠
缺點 - >長期執行,難以除錯,許多成本(部署許多應用程式,許多資源,如資料庫,快取等),存在非常晚的反饋
模擬Mock其他服務;
優點 - >非常快速的反饋,無需設定基礎設施
缺點 - >不可靠,你可以對K8s的prod測試和失敗檢查
為解決這些問題,建立了Spring Cloud Contract。
我在開發應用程式的新功能時遵循這些步驟;
1. 準備合同。
2. 從準備好的合同中生成測試。
3. 採用TDD和紅綠色風格編碼。
4. 功能完成後,你可以建立存根(合約)jar。
5. 消費者可以使用這個存根罐來整合api。
好吧,讓我們按這個步驟編碼;
首先,我們需要使用Groovy DSL建立合同,如下所示;
importorg.springframework.cloud.contract.spec.Contract
Contract.make {
description"should retrieve account"
request {
method GET()
headers {
accept(applicationJson())
}
url ('/api/v1/accounts'){
queryParameters {
parameter(
"accountId",1L)
}
}
}
response {
status OK()
headers {
contentType(applicationJson())
}
body(file(
"retrieveAccountResponse.json"))
}
}
這是一個在生產者端檢索帳戶的合同定義,我們為檢索帳戶製作了這個樣本合同。請求'api/v1/accounts'端點是使用HTTP get方法和查詢引數'accountId。
響應中指定Http標頭為json,最後我們期望響應狀態應該是正常的(200)並且響應頭contentType應該是json並且響應體應該等於json響應檔案。響應內容如下;
{
"name": "Name",
"surname": "Surname",
"gender": "Gender",
"gsmNumber": "GsmNumber",
"identifier": "Identifier",
"createdDate":1514851199,
"updatedDate":1514851199
}
在生成測試類之前,我們應該配置合同外掛;
org.springframework.cloud
spring-cloud-starter-contract-verifier
test
org.springframework.boot
spring-boot-maven-plugin
org.springframework.cloud
spring-cloud-contract-maven-plugin
true
com.caysever.producer.ProducerBaseContractTest
EXPLICIT
生產者方面的pom.xml
你可以使用TDD樣式從合同和編碼中生成測試類,這可以透過generateTests maven目標來做到這一點 - > mvn org.springframework.cloud:spring-cloud-contract-maven-plugin:2.0.1.RELEASE:generateTests
生成的測試置於target/generated-test-sources下,生成測試如下程式碼:
publicclassContractVerifierTestextendsProducerBaseContractTest {
@Test
publicvoidvalidate_retrieveAccountContract() throws Exception {
//given:
RequestSpecification request =given()
.header(
"Accept", "application/json");
//when:
Response response =given().spec(request)
.queryParam(
"accountId","1")
.get(
"/api/v1/accounts");
//then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header(
"Content-Type")).matches("application/json.*");
//and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).field(
"['surname']").isEqualTo("Surname");
assertThatJson(parsedJson).field(
"['updatedDate']").isEqualTo(1514851199);
assertThatJson(parsedJson).field(
"['gender']").isEqualTo("Gender");
assertThatJson(parsedJson).field(
"['name']").isEqualTo("Name");
assertThatJson(parsedJson).field(
"['createdDate']").isEqualTo(1514851199);
assertThatJson(parsedJson).field(
"['identifier']").isEqualTo("Identifier");
assertThatJson(parsedJson).field(
"['gsmNumber']").isEqualTo("GsmNumber");
}
你現在可以將其作為正常的junit測試執行,測試透過後,可以與你的客戶和消費者分享你的合同。
注意:
當修改端點(如重新命名url或新增/刪除引數)時,應修改合同,如果你不修改,則構建無法透過。
Spring cloud contract外掛為你生成存根stub的jar包,可以將其部署到artifactory或本地參考local repo,Spring雲契約支援不同的存根模式,例如classpath或本地m2 repo或遠端artifactory(神器?),我們這裡將使用本地m2模式。
讓我們看看如何消費存根stub:
@ExtendWith(SpringExtension.class)
@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureStubRunner(ids ="com.caysever:producer:+:8090", stubsMode = StubRunnerProperties.StubsMode.LOCAL)
classProducerVerifierTest {
@Autowired
privateWebTestClient webTestClient;
@Test
voidshould_retrieveAccountById() {
//given
Long accountId = 1L;
//when
Account account = webTestClient.get()
.uri(
"{accountId}", accountId)
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody(Account.class)
.returnResult()
.getResponseBody();
//then
assertThat(account).isNotNull();
assertThat(account.getName()).isEqualTo(
"Name");
assertThat(account.getSurname()).isEqualTo(
"Surname");
assertThat(account.getGender()).isEqualTo(
"Gender");
assertThat(account.getGsmNumber()).isEqualTo(
"GsmNumber");
assertThat(account.getIdentifier()).isEqualTo(
"Identifier");
assertThat(account.getCreatedDate()).isEqualTo(1514851199);
assertThat(account.getUpdatedDate()).isEqualTo(1514851199);
}
}
使用@AutoConfigureStubRunner註釋Spring設定wiremock伺服器,真正的生產者api應該在8090埠,我們建立REST http請求並斷言響應資料。如果任何步驟發生失敗,則測試交付的CI / CD管道都不會透過,即使在你的本地環境而不是CI伺服器上
作者:Java高階技術
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2001/viewspace-2820014/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Spring Boot 整合 RabbitMQ 訊息事務(消費者)Spring BootMQ
- 未來消費者系列研究:大資料驅動的消費者洞察大資料
- 使用Spring Boot REST API進行測試驅動開發Spring BootRESTAPI
- 移動消費者的下一站:中國移動消費者調研
- RocketMQ之消費者啟動與消費流程MQ
- sarama的消費者組分析、使用
- 是什麼原因驅動著消費者復購瓶裝水?
- 使用 rocketmq-spring-boot-starter 來配置、傳送和消費 RocketMQ 訊息MQSpringboot
- 飛豬:消費者驅動新零售時代酒店變革
- Kakfa -- 消費者啟動流程
- RocketMQ -- 消費者啟動流程MQ
- 企業級 Spring Boot 教程 (十四)用restTemplate消費服務Spring BootREST
- kafka消費者消費訊息的流程Kafka
- 戰略驅動多向協同,捷信築牢消費者權益底座
- 支援自動伸縮的消費者模式模式
- Spring Boot+RabbitMQ 通過fanout模式實現訊息接收(支援消費者多例項部署)Spring BootMQ模式
- Spring Boot(三):Spring Boot中的事件的使用 與Spring Boot啟動流程(Event 事件 和 Listeners監聽器)Spring Boot事件
- MAGNA:情緒驅動消費旅程研究報告
- Spring Boot 基於註解驅動原始碼分析--自動配置Spring Boot原始碼
- Kafka 消費組消費者分配策略Kafka
- 使用Spring Boot的10多個免費開源專案Spring Boot
- Spring Boot 基於註解驅動原始碼分析--自動掃描Spring Boot原始碼
- 生產者消費者
- CTR:新冠疫情下的女性消費者動態
- Spring Boot 2.0(四):使用 Docker 部署 Spring BootSpring BootDocker
- 使用BlockQueue實現生產者和消費者模式BloC模式
- 使用Disruptor實現生產者和消費者模型模型
- Spring Cloud Alibaba 使用Feign進行服務消費SpringCloud
- Spring Cloud Alibaba 使用RestTemplate進行服務消費SpringCloudREST
- 勞動合同免費分享!需要的看過來
- 如何使用Spring Boot的ProfilesSpring Boot
- 使用Spring Boot開發的10個免費開源專案Spring Boot
- Rabbitmq消費者冪等性(不重複消費)MQ
- Spring:事件驅動Spring事件
- RocketMQ - 消費者概述MQ
- Kafka 消費者解析Kafka
- Spring Boot Admin 使用Spring Boot
- Spring Boot 使用1Spring Boot