javascript
在Spring WebFlux中创建多个RouterFunction
在這篇文章中,我們將研究在Spring WebFlux中為不同的邏輯域定義多個路由器功能。 如果您正在創建“微服務”,則可能不會出現問題,因為您很可能僅在每個服務的單個域中工作,但是如果不是這樣,則可能需要在應用程序中包含多個域,用戶或您自己的服務可以進行交互。 做到這一點的代碼就像我希望的那樣簡單,可以用幾句話來解釋。 為了使本文更加有趣,我們將看一些使這一切成為可能的Spring代碼。
如果您不熟悉WebFlux,建議您閱讀我以前的文章[使用Spring WebFlux做事]( https://lankydanblog.com/2018/03/15/doing-stuff-with-spring-webflux/ ),在這里,我寫了一些有關該主題的詳盡示例和解釋。
因此,讓我們先設置場景。 您的應用程序內有兩個不同的域,例如人和地點。 您可能希望不僅在邏輯上而且在代碼內使它們彼此分開。 為此,您需要一種獨立于彼此域定義路由的方法。 這就是我們將在這篇文章中看到的內容。
如果您認為您已經知道該問題的答案,那么您可能是對的。 真的就是這么簡單。 讓我們繼續努力吧。 要僅為人員域創建路由,請創建一個RouterFunction bean,該bean映射到相關的處理程序函數,如下所示。
@Configuration public class MyRouter {// works for a single bean@Beanpublic RouterFunction<ServerResponse> routes(PersonHandler personHandler) {return RouterFunctions.route(GET("/people/{id}").and(accept(APPLICATION_JSON)), personHandler::get).andRoute(GET("/people").and(accept(APPLICATION_JSON)), personHandler::all).andRoute(POST("/people").and(accept(APPLICATION_JSON)).and(contentType(APPLICATION_JSON)), personHandler::post).andRoute(PUT("/people/{id}").and(accept(APPLICATION_JSON)).and(contentType(APPLICATION_JSON)), personHandler::put).andRoute(DELETE("/people/{id}"), personHandler::delete).andRoute(GET("/people/country/{country}").and(accept(APPLICATION_JSON)), personHandler::getByCountry);} }這將創建到PersonHandler各種處理程序函數的PersonHandler 。
因此,現在我們要為位置邏輯添加路由。 我們可以簡單地將路由添加到該bean,如下所示。
@Configuration public class MyRouter {// not ideal!@Beanpublic RouterFunction<ServerResponse> routes(PersonHandler personHandler, LocationHandler locationHandler) {return RouterFunctions.route(GET("/people/{id}").and(accept(APPLICATION_JSON)), personHandler::get).andRoute(GET("/people").and(accept(APPLICATION_JSON)), personHandler::all).andRoute(POST("/people").and(accept(APPLICATION_JSON)).and(contentType(APPLICATION_JSON)), personHandler::post).andRoute(PUT("/people/{id}").and(accept(APPLICATION_JSON)).and(contentType(APPLICATION_JSON)), personHandler::put).andRoute(DELETE("/people/{id}"), personHandler::delete).andRoute(GET("/people/country/{country}").and(accept(APPLICATION_JSON)), personHandler::getByCountry).andRoute(GET("/locations/{id}").and(accept(APPLICATION_JSON)), locationHandler::get);} }Bean現在包含對LocationHandler的引用,因此可以設置位置路由。 該解決方案的問題在于它需要將代碼耦合在一起。 此外,如果您需要添加更多的處理程序,很快就會被注入到此bean中的依賴項數量所淹沒。
解決此問題的方法是創建多個RouterFunction bean。 而已。 因此,如果我們在人員域中創建一個,例如PersonRouter然后在位置域中創建一個名為LocationRouter域,則每個域都可以定義所需的路由,其余的將由Spring完成。 之所以可行,是因為Spring會遍歷應用程序上下文并查找或創建任何RouterFunction bean,并將它們合并為一個函數供以后使用。
使用此信息,我們可以編寫以下代碼。
@Configuration public class PersonRouter {// solution@Beanpublic RouterFunction<ServerResponse> peopleRoutes(PersonHandler personHandler) {return RouterFunctions.route(GET("/people/{id}").and(accept(APPLICATION_JSON)), personHandler::get).andRoute(GET("/people").and(accept(APPLICATION_JSON)), personHandler::all).andRoute(POST("/people").and(accept(APPLICATION_JSON)).and(contentType(APPLICATION_JSON)), personHandler::post).andRoute(PUT("/people/{id}").and(accept(APPLICATION_JSON)).and(contentType(APPLICATION_JSON)), personHandler::put).andRoute(DELETE("/people/{id}"), personHandler::delete).andRoute(GET("/people/country/{country}").and(accept(APPLICATION_JSON)), personHandler::getByCountry);} }和
@Configuration public class LocationRouter {// solution@Beanpublic RouterFunction<ServerResponse> locationRoutes(LocationHandler locationHandler) {return RouterFunctions.route(GET("/locations/{id}").and(accept(APPLICATION_JSON)), locationHandler::get);} }PersonRouter可以與其他人/人相關的代碼保持在一起,而LocationRouter可以做到相同。
為了使它變得更有趣,為什么要這樣做?
RouterFunctionMapping是檢索在應用程序上下文內創建的所有RouterFunction Bean的類。 RouterFunctionMapping bean是在WebFluxConfigurationSupport中創建的, WebFluxConfigurationSupport是Spring WebFlux配置的中心。 通過在配置類中包含@EnableWebFlux批注或依靠自動配置,將啟動一系列事件,收集我們所有的RouterFunction就是其中之一。
下面是RouterFunctionMapping類。 我刪除了它的構造函數和一些方法,以使此處的代碼片段更容易理解。
public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean {@Nullableprivate RouterFunction<?> routerFunction;private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();// constructors// getRouterFunction// setMessageReaders@Overridepublic void afterPropertiesSet() throws Exception {if (CollectionUtils.isEmpty(this.messageReaders)) {ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();this.messageReaders = codecConfigurer.getReaders();}if (this.routerFunction == null) {initRouterFunctions();}}/*** Initialized the router functions by detecting them in the application context.*/protected void initRouterFunctions() {if (logger.isDebugEnabled()) {logger.debug("Looking for router functions in application context: " +getApplicationContext());}List<RouterFunction<?>> routerFunctions = routerFunctions();if (!CollectionUtils.isEmpty(routerFunctions) && logger.isInfoEnabled()) {routerFunctions.forEach(routerFunction -> logger.info("Mapped " + routerFunction));}this.routerFunction = routerFunctions.stream().reduce(RouterFunction::andOther).orElse(null);}private List<RouterFunction<?>> routerFunctions() {SortedRouterFunctionsContainer container = new SortedRouterFunctionsContainer();obtainApplicationContext().getAutowireCapableBeanFactory().autowireBean(container);return CollectionUtils.isEmpty(container.routerFunctions) ? Collections.emptyList() :container.routerFunctions;}// getHandlerInternalprivate static class SortedRouterFunctionsContainer {@Nullableprivate List<RouterFunction<?>> routerFunctions;@Autowired(required = false)public void setRouterFunctions(List<RouterFunction<?>> routerFunctions) {this.routerFunctions = routerFunctions;}}}檢索所有路由的路徑始于afterPropertiesSet ,該RouterFunctionMapping在創建RouterFunctionMapping bean之后調用。 由于內部的RouterFunction為null因此它會調用initRouterFunctions觸發一系列導致routerFunctions執行的routerFunctions 。 通過從應用程序上下文注入所有RouterFunction構造一個新的SortedRouterFunctionsContainer (私有靜態類),將其設置為routerFunctions字段。 這是可行的,因為在注入List<T>時,Spring會注入所有T類型的bean。 現在檢索到的RouterFunction組合在一起,形成一個RouterFunction ,從現在開始將其用于將所有傳入請求路由到適當的處理程序。
這里的所有都是它的。 總之,為不同的業務域定義多個RouterFunction非常簡單,因為您只需在它們最有意義的任何區域中創建它們,Spring就會開始獲取它們。 為了使某些魔術變得神秘,我們研究了RouterFunctionMapping以了解如何收集和組合我們創建的RouterFunction ,以便可以將它們用于將請求路由到處理程序。 作為結束語,我確實了解到,這篇文章在某些方面是微不足道的,但有時看似明顯的信息可能會很有幫助。
如果您還沒有這樣做,我建議您看一下我以前的文章《使用Spring WebFlux做事》( https://lankydanblog.com/2018/03/15/doing-stuff-with-spring-webflux/ )。
最后,如果您發現這篇文章很有幫助,并且希望在我撰寫新文章時保持關注,那么可以在Twitter上通過@LankyDanDev關注我。
翻譯自: https://www.javacodegeeks.com/2018/03/creating-multiple-routerfunctions-in-spring-webflux.html
總結
以上是生活随笔為你收集整理的在Spring WebFlux中创建多个RouterFunction的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AMD 针对《匹诺曹的谎言》发布专用驱动
- 下一篇: JSON补丁:JSON-P 1.1概述系