Spring Cloud系列–網關模式
1.概述
到目前為止,在我們的雲應用程序中,我們已經使用了網關模式來支持兩個主要功能。
首先,我們將客戶與每項服務隔離開,從而消除了跨域支持的需求。接下來,我們使用Eureka實現了服務定位實例。
在本文中,我們將研究如何使用網關模式通過單個請求從多個服務中檢索數據。為此,我們將Feign引入網關,以幫助將API調用寫入我們的服務。
要閱讀有關如何使用Feign客戶端的信息,請查看本文。
Spring Cloud現在還提供了實現此模式的Spring Cloud Gateway項目。
2.設定
讓我們打開gateway
服務器的pom.xml
並添加Feign的依賴項:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
供參考–我們可以在Maven Central
( spring-cloud-starter-feign )上找到最新版本。
現在我們已經支持構建Feign客戶端,讓我們在GatewayApplication.java
啟用它:
@EnableFeignClients
public class GatewayApplication { ... }
現在,讓我們為圖書和評級服務設置Feign客戶。
3.假客戶
3.1。圖書客戶
讓我們創建一個名為BooksClient.java
的新接口:
@FeignClient("book-service")
public interface BooksClient {
@RequestMapping(value = "/books/{bookId}", method = RequestMethod.GET)
Book getBookById(@PathVariable("bookId") Long bookId);
}
通過這個接口,我們指示Spring創建一個Feign客戶端,該客戶端將訪問“ /books/{bookId
}”端點。調用時, getBookById
方法將對端點進行HTTP調用,並使用bookId
參數。
為了完成這項工作,我們需要添加Book.java
DTO:
@JsonIgnoreProperties(ignoreUnknown = true)
public class Book {
private Long id;
private String author;
private String title;
private List<Rating> ratings;
// getters and setters
}
讓我們繼續到RatingsClient
。
3.2。評級客戶
讓我們創建一個稱為RatingsClient
的接口:
@FeignClient("rating-service")
public interface RatingsClient {
@RequestMapping(value = "/ratings", method = RequestMethod.GET)
List<Rating> getRatingsByBookId(
@RequestParam("bookId") Long bookId,
@RequestHeader("Cookie") String session);
}
與BookClient
一樣,此處公開的方法將對我們的評級服務進行重新調用,並返回一本書的評級列表。
但是,此端點是安全的。為了能夠正確訪問此端點,我們需要將用戶的會話傳遞給請求。
我們使用@RequestHeader
批註進行此操作。這將指示Feign將變量的值寫入請求的標頭。在本例中,我們正在寫Cookie
頭,因為Spring Session將在cookie中尋找我們的會話。
在本例中,我們正在寫Cookie
頭,因為Spring Session將在cookie中尋找我們的會話。
最後,讓我們添加一個Rating.java
DTO:
@JsonIgnoreProperties(ignoreUnknown = true)
public class Rating {
private Long id;
private Long bookId;
private int stars;
}
現在,兩個客戶端均已完成。讓我們使用它們!
4.合併請求
網關模式的一種常見用例是使端點封裝通常稱為服務的端點。通過減少客戶端請求的數量,可以提高性能。
為此,我們創建一個控制器並將其命名為CombinedController.java
:
@RestController
@RequestMapping("/combined")
public class CombinedController { ... }
接下來,讓我們連接新創建的偽裝客戶:
private BooksClient booksClient;
private RatingsClient ratingsClient;
@Autowired
public CombinedController(
BooksClient booksClient,
RatingsClient ratingsClient) {
this.booksClient = booksClient;
this.ratingsClient = ratingsClient;
}
最後,讓我們創建一個GET請求,該請求將這兩個端點結合起來,並返回加載了其評分的一本書:
@GetMapping
public Book getCombinedResponse(
@RequestParam Long bookId,
@CookieValue("SESSION") String session) {
Book book = booksClient.getBookById(bookId);
List<Rating> ratings = ratingsClient.getRatingsByBookId(bookId, "SESSION="+session);
book.setRatings(ratings);
return book;
}
注意,我們正在使用@CookieValue
註釋設置會話值,該註釋將從請求中提取出來。
在那裡!我們在網關中有一個組合的端點,可以減少客戶端與系統之間的網絡調用!
5.測試
確保我們的新端點正常運行。
導航到LiveTest.java
,讓我們為組合的端點添加一個測試:
@Test
public void accessCombinedEndpoint() {
Response response = RestAssured.given()
.auth()
.form("user", "password", formConfig)
.get(ROOT_URI + "/combined?bookId=1");
assertEquals(HttpStatus.OK.value(), response.getStatusCode());
assertNotNull(response.getBody());
Book result = response.as(Book.class);
assertEquals(new Long(1), result.getId());
assertNotNull(result.getRatings());
assertTrue(result.getRatings().size() > 0);
}
啟動Redis,然後在我們的應用程序中運行每個服務: config, discovery, zipkin,
gateway
, book
和rating
服務。
一切就緒後,請運行新測試以確認其正常運行。
六,結論
我們已經看到瞭如何將Feign集成到我們的網關中以構建專用端點。我們可以利用這些信息來構建我們需要支持的任何API。最重要的是,我們看到我們並沒有被只暴露單個資源的“一刀切”的API所困。
使用網關模式,我們可以根據每個客戶的需求來設置我們的網關服務。這樣就產生了去耦,使我們的服務可以自由地根據需要進行發展,保持精簡併專注於應用程序的一個領域。