在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之后调用。 由于内部的RouterFunctionnull因此它会调用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/347690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cstart做int型转换运算Java,java 实验报告1.docx

甘肃政法学院本科生实验报告(一)姓名:俞晓学院:信息工程学院专业:信息管理与信息系统班级:13级信管班实验课程名称:JAVA SE课程实验指导教师&#xff1a;李瑞生 教师实验成绩&#xff1a;实验日期: 2015 年 3 月 24 日开课时间&#xff1a; 2014-2015 学年 第二 学期甘肃政法学…

Java面向对象(15)--static关键字静态理解与使用

类属性作为该类各个对象之间共享的变量。在设计类时,分析哪些属性不因对象的不同而改变&#xff0c;将这些属性设置为类属性。如果方法与调用者无关&#xff0c;则这样的方法通常被声明为类方法&#xff0c;由于不需要创建对象就可以调用类方法&#xff0c;从而简化了方法的调用…

JSON补丁:JSON-P 1.1概述系列

Java EE 8包括对JSON处理API的更新&#xff0c;并使其与JSON的最新IEFT标准保持同步。 他们是&#xff1a; JSON指针 RFC 6901 JSON补丁 RFC 6902 JSON合并修补程序RFC 7396 我将在这个迷你系列中涵盖这些主题。 入门 要开始使用JSON-P&#xff0c;您将需要Maven中央存储库…

Java面向对象(16)--单例(Singleton)设计模式

所谓类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象&#xff0c;我们首先必须将类的构造器的访问权限设…

mac php 超时,PHP---Mac上开启php错误提示

发现在使用mac 上 PHP开发项目的时候&#xff0c;程序代码错误的时候没有错误提示&#xff0c;只是提示白板。研究和查找资料才调整了一下; 步骤如下&#xff1a;1.找到php.ini文件如图所示&#xff1a;1)找到 display_errors Off &#xff0c;把Off 改为 On . 最后为 display…

tomcat 轮询_用Spring长轮询Tomcat

tomcat 轮询就像喜剧演员弗兰基 豪威尔 &#xff08; Frankie Howerd&#xff09;所说的“噢&#xff0c;小姐小姐” &#xff0c;但足够多的英国影射和双重诱惑&#xff0c;因为长轮询Tomcat对隔壁的闷气不是某种性的偏见&#xff0c;这是一种技术&#xff08;或更像是一种hac…

单例(Singleton)设计模式应用场景

网站的计数器&#xff0c;一般也是单例模式实现&#xff0c;否则难以同步。 应用程序的日志应用&#xff0c;一般都使用单例模式实现&#xff0c;这一般是由于共享的日志文件一直处于打开状态&#xff0c;因为只能有一个实例去操作&#xff0c;否则内容不好追加。 数据库连接…

免费网络研讨会:Java应用程序中的吞咽异常

1月30日参加我们的网络研讨会&#xff0c;以发现Java应用程序中的“隐藏”异常。 如果一棵树落在森林中&#xff0c;但是没有写到原木上&#xff0c;它会发出声音吗&#xff1f; 答案是肯定的。 这些类型的错误可能会对用户体验造成严重影响&#xff0c;而没有根本原因的可见性…

php bloginfo templatedirectory,WordPress函数:bloginfo(显示博客信息)

描述显示你的博客信息&#xff0c;大部分都是显示WordPress管理界面的 用户资料 和 常规设置 中的信息。它可以在模板文件的任何地方使用。一般 bloginfo() 都是用来直接在浏览器中输出内容的。如果你需要在PHP中返回值的话&#xff0c;那么请用 get_bloginfo()。用法<?php…

Java面向对象(17)--类代码块

静态代码块&#xff1a;用static 修饰的代码块 ①可以有输出语句。 ②可以对类的属性、类的声明进行初始化操作。 ③不可以对非静态的属性初始化&#xff0c;即&#xff1a;不可以调用非静态的属性和方法。 ④ 静态代码块随着类的加载而加载并执行&#xff0c;类加载一次&…

js 和java有关系吗,javascript和JAVA有什么关系

2017-07-28Java调用javascriptpackage co。test;import java。io。FileReader;import java。io。LineNumberReader;import org。mozilla。 javascript。Context;import org。mozilla。javascript。Function;import org。mozilla。javascript。Scriptable;public class JSExplor…

gson 入门_Google GSON入门

gson 入门在Java世界中&#xff0c;JSON已成为事实上的XML数据交换格式标准&#xff0c;因为它的易用性和传输效率高。 如果您不了解JSON&#xff0c;那就是Javascript对象表示法&#xff0c;这是一种基于文本的数据交换格式&#xff0c;是名称-值的集合&#xff0c;其中名称严…

Java面向对象(18)--final关键字使用

在Java中声明类、变量和方法时&#xff0c;可使用关键字final来修饰,表示“最终的”。 final标记的类不能被继承&#xff0c;提高安全性&#xff0c;提高程序的可读性 如&#xff1a;String类、System类、StringBuffer类。 final标记的方法不能被子类重写 如&#xff1a;Objec…

php 高级搜索下拉框,高级搜索页面advancedsearch.php调用自定义字段

下面跟大家谈的是关于”如何在在高级搜索页面advancedsearch.php调用自定义字段“方法&#xff1a;步骤&#xff1a;找到advancedsearch.php页面。$query "select main.id as aid,main.*,main.description as description1, type.* from $maintable main left join dede2…

创新设计模式:抽象工厂模式

抽象工厂模式是一种创建模式&#xff0c;是与构建器和工厂模式一起最受欢迎的模式之一。 使用创建模式是为了创建对象&#xff0c;而不是直接使用构造函数创建对象。 抽象工厂模式提供了一种封装一组具有共同主题的单个工厂而无需指定其具体类的方法。 采用该模式的目的是使对…

php算法台阶,php如何解决青蛙跳台阶的问题(代码)

本篇文章给大家带来的内容是关于php如何解决青蛙跳台阶的问题(代码)&#xff0c;有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对你有所帮助。一只青蛙一次可以跳上1级台阶&#xff0c;也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后…

Java面向对象(19)--抽象类与抽象方法abstract

用abstract关键字来修饰一个类&#xff0c;这个类叫做抽象类。 用abstract来修饰一个方法&#xff0c;该方法叫做抽象方法。 抽象方法&#xff1a;只有方法的声明&#xff0c;没有方法的实现。以分号结束&#xff1a; 比如&#xff1a;public abstract void talk(); 含有抽象…

php检测一个变量是否设置函数,php如何判断变量是否有设置的函数

php判断变量是否有设置的函数的方法&#xff1a;可以利用isset()函数来进行判断。isset()函数用于检测变量是否已设置并且非NULL。如果指定变量存在且不为NULL&#xff0c;则返回TRUE&#xff0c;否则返回FALSE。isset() 函数用于检测变量是否已设置并且非 NULL。(推荐教程&…

Java面向对象(20)--接口

接口的使用 ①接口使用interface来定义 ②Java中&#xff0c;接口和类是并列的两个结构 ③定义接口中的成员 JDK7及以前:只能定义全局常量和抽象方法 全局常量: public static final修饰的&#xff0c;书写时&#xff0c;可以省略不写 抽象方法: public abstract修饰的&#x…

java轮询文件停止线程,java 运行多线程轮询时,外部停止轮询

1&#xff0c;先建一个Map/*** 创建一个Map用于存放线程id对象集合&#xff0c;主要是用于到达岗亭之后扫码付费&#xff0c;如果人工收费就需要关闭线程&#xff0c;key是停车记录Id&#xff0c;*/public static MapMAPTHREAD new HashMap();2.建一个线程类继承Runnable/*** …