使用Vert.x + SpringBoot编写业务系统 - 知乎

标签: | 发表时间:2021-10-31 11:58 | 作者:
出处:https://zhuanlan.zhihu.com

这一期文章主要为大家介绍如何将Vert.x与SpringBoot结合起来编写最最最常见的业务系统,即数据库增删改查。

谈两句SpringBoot

SpringBoot大家都很熟了,一个快速开发框架,其最大的特点是可将Spring应用打成可执行jar包,从而不再依赖外部容器,如Tomcat。可能绝大多数人在使用SpringBoot时一定离不了嵌入式Tomcat, 从而造成了一想到SpringBoot就会将其与SpringMVC联系在一起的现象。其实我们可以 只使用SpringBoot的一键执行和提供Spring环境的特性,Web层直接替换成Vert.x. 此外,一些短时执行的任务也可以用这种方式来写,简直不能更爽。

Vertx-web的请求路由

上一篇写的Http Server是没有路由的,所有的请求都会由同一个Handler处理。如果是只提供一个简单的API服务这样是没有问题的,但在实际业务系统中一般接口数量都比较多,这时候就需要一个路由组件来将不同的Path, Method映射到不同的handler上,使用方法如下:

          HttpServerserver=vertx.createHttpServer();Routerrouter=Router.router(vertx);// (0)router.route("/a/b/c/path")// (1).handler(BodyHandler.create())// (2).handler(demoHandler)// (3).blockingHandler(blockHandler);// (4)server.requestHandler(router::accept)// (5).listen(8080);

(0): 构造一个Router。

(1): 添加对 /a/b/c/path的路由。这里也可以使用重载的带有HTTP Method的方法。

(2): 当收到path为 /a/b/c/path的请求时,先调用 BodyHandler。这里 BodyHandler是Vert.x提供的处理器,只有在请求处理链路的开头添加了此Handler我们才能在后续的Handler中拿到请求体。

(3): 添加我们的业务处理器, 此处理器会在NIO线程中执行。

(4): 添加含有阻塞调用的业务处理器,此处理器会在worker线程池中执行,不会block NIO线程。

(5): 将Router的Handler设为整个HTTP Server的Handler。

其中Handler是一个函数式接口,定义如下:

          @FunctionalInterfacepublicinterfaceHandler<E>{/*** Something has happened, so handle it.** @param event  the event to handle*/voidhandle(Eevent);}

可见,vertx添加请求处理器的过程非常简单,而且写起来也很爽。

不过这里还是会有一个问题,我们的服务会有大量的Handler, 大量的路由,这时候就只能在这里罗列一堆方法调用吗?当然不用,这些重复性的工作一定是可以在框架层面处理掉的,比如,你可以选择使用我写的 spring-boot-starter-vertx, 用了以后就可以像SpringMVC里 @Controller注解一样直接定义Handler了,starter会在启动时自动扫描添加,像这样:

          @Component// @BlockedHandler@Slf4jpublicclassDemoHandlerimplementsHandler<RoutingContext>{@Overridepublicvoidhandle(RoutingContextroute){log.info("invoke DemoHandler, path: {}",route.request().path());route.response().end("ok");}}

如果Handler需要在worker线程池中调用,那么只需要添加一个 @BlockedHandler注解即可。

是不是很方便?

如何处理数据库查询

数据库查询操作其实代表的是阻塞调用。在Vert.x Web应用中,我们有两种方式来处理block调用,一种就是像上面说的那样,将含有block调用的代码集中到一个Handler中然后注册成blockingHandler; 另一种则是像node.js那样使用回调。其中回调又可以分成两类,一是使用 vert.x封装好的异步JDBC,里面所有的block操作都会多一个注册回调方法的参数。这种方式我个人觉得如果你是刚刚入坑vert.x话那就很不推荐,因为它会让你对回调产生恐惧。这里建议使用更传统点的方法,即继续使用你喜欢的持久化框架,只不过是在调用时将这部分代码提交到worker线程池中执行。下面我们用代码说话。

假设我们需要做两次数据库查询,只有拿到两次查询的结果才能执行后面的逻辑,这种情况在业务系统中是非常常见的。用回调方式的代码长这样:

          @Overridepublicvoidhandle(RoutingContextroute){log.info("invoke DemoHandler, path: {}",route.request().path());// (0)Future<String>fut1=Future.future();Future<String>fut2=Future.future();// 执行block调用route.vertx()// (1).executeBlocking(fut->{Stringresult=demoService.blockingLogic(1);// (2)fut.complete(result);// (3)},fut1.completer()// (4));// 执行block调用route.vertx().executeBlocking(fut->{Stringresult=demoService.blockingLogic(2);fut.complete(result);},fut2.completer());// 组合结果CompositeFuture.all(fut1,fut2).setHandler(ar->{// (5)if(!ar.succeeded()){// (6)log.error("",ar.cause());route.response().end("error");return;}log.info("final step");List<String>resultList=ar.result().list();// (7)route.response().end(resultList.toString());});}

(0): 构造两个Future对象,用来协调、同步两个异步调用

(1): 从一下文中获取vertx对象,调用 executeBlocking()方法向worker线程池中提交任务

(2): 调用会发生阻塞的数据库查询方法

(3): 调用传进来的Future对象的 complete()方法通知vert.x业务逻辑成功完成,并将执行的结果对象传递进来

(4): 将我们定义的Future对象标记为成功或失败。如果(2)或(3)抛出了异常,那么fut2会被标记为失败,反之成功

(5): 使用 CompositeFuture工具类的 all()方法将上面定义的两个Feature组合起来,并注册一个回调方法,此方法会在fut1, fut2全部成功或有一个失败时触发。

(6): 回调触发后,要先判断结果是成功还是失败

(7): 取出两个DB查询的结果

可以看到,业务逻辑被各种回调分散到了不同的Handler中。这就是使用异步框架最主要的工程代价。

组合起来

我写了一个Demo web项目,它基于上面提到的 spring-boot-starter-vertx项目,提供一个 GET /user?username=xxx查询接口,使用Mybatis做持久化层实现DB查询。麻雀虽小五脏俱全!

https://github.com/wanghongfei/all-about-vertx-4

相关 [vert springboot 业务] 推荐:

使用Vert.x + SpringBoot编写业务系统 - 知乎

- -
这一期文章主要为大家介绍如何将Vert.x与SpringBoot结合起来编写最最最常见的业务系统,即数据库增删改查. 谈两句SpringBoot. SpringBoot大家都很熟了,一个快速开发框架,其最大的特点是可将Spring应用打成可执行jar包,从而不再依赖外部容器,如Tomcat. 可能绝大多数人在使用SpringBoot时一定离不了嵌入式Tomcat, 从而造成了一想到SpringBoot就会将其与SpringMVC联系在一起的现象.

SpringBoot-Metrics监控

- -
Metrics基本上是成熟公司里面必须做的一件事情,简单点来说就是对应用的监控,之前在一些技术不成熟的公司其实是不了解这种概念,因为业务跟技术是相关的. 当业务庞大起来,技术也会相对复杂起来,对这些复杂的系统进行监控就存在必要性了,特别是在soa化的系统中,完整一个软件的功能分布在各个系统中,针对这些功能进行监控就更必要了.

SpringBoot的事务管理

- - ImportNew
Springboot内部提供的事务管理器是根据autoconfigure来进行决定的. 比如当使用jpa的时候,也就是pom中加入了spring-boot-starter-data-jpa这个starter之后(之前我们分析过 springboot的自动化配置原理). Springboot会构造一个JpaTransactionManager这个事务管理器.

springboot aop日志记录

- - 编程语言 - ITeye博客
一、POM增加AOP JAR包. 三、SysAspect类. 注:@annotation(cn.com.hfai.controller.system.Logweb) 一定要指定Logweb类. 四、在Controller类的方法之上加上注解 @Logweb 即可. 注:这个只是打印在控制台上,若想放到数据库中,则需要增加操作数据库的业务代码.

springboot单元测试技术

- - 海思
整个软件交付过程中,单元测试阶段是一个能够最早发现问题,并且可以重复回归问题的阶段,在单元测试阶段做的测试越充分,软件质量就越能得到保证. 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-unit-test.

K8S部署SpringBoot应用_都超的博客-CSDN博客_k8s springboot

- -
K8S环境机器做部署用,推荐一主双从. Docker Harbor私有仓库,准备完成后在需要使用仓库的机器docker login. 开发机器需要Docker环境,build及push使用. 一、构建基本Springboot工程,本例所用版本及结构如下图. 创建测试代码,简单打印几行log. .

springboot集成shiro 实现权限控制

- - CSDN博客编程语言推荐文章
apache shiro 是一个轻量级的身份验证与授权框架,与spring security 相比较,简单易用,灵活性高,springboot本身是提供了对security的支持,毕竟是自家的东西. springboot暂时没有集成shiro,这得自己配. 本文实现从数据库读取用户信息,获取当前用户的权限或角色,通过配置文件过滤用户的角色或权限.

让SpringBoot启动更快一点

- - ImportNew
这是 2018 Spring One Platform 中的一场会议. 看完会议视频,我自己动手试了一下. 还没有观看视频的朋友推荐看一下,非常有意思. ↓我使用的是 OpenJDK 11. ❯ java --version openjdk 11.0.1 2018-10-16 OpenJDK Runtime Environment 18.9 (build 11.0.1+13) OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode).

springboot 整合retry(重试机制) - 简书

- -
当我们调用一个接口可能由于网络等原因造成第一次失败,再去尝试就成功了,这就是重试机制,spring支持重试机制,并且在Spring Cloud中可以与Hystaix结合使用,可以避免访问到已经不正常的实例. 写一个简单的demo,加入依赖:. @EnableRetry注解,表示启用重试机制. 定义一个简单的controller层:.

基于springboot的freemarker创建指定格式的word文档

- - 互联网 - ITeye博客
       在web或其他应用中,经常我们需要导出或者预览word文档,比较实际的例子有招聘网站上预览或者导出个人简历,使用POI导出excel会非常的方便,但是如果想导出word,由于其格式控制非常复杂,故而使用POI将会非常麻烦,而FreeMarker则可以较好的解决这个问题;并且,根据FreeMarker的实现原理,预览word也会变得非常简单.