vert.x 分布式锁_使用Vert.x进行响应式开发

vert.x 分布式锁

最近,似乎我们正在听到有关Java的最新和最好的框架的消息。 Ninja , SparkJava和Play等工具; 但是每个人都固执己见,使您感到需要重新设计整个应用程序以利用它们的出色功能。 这就是为什么当我发现Vert.x时令我感到宽慰的原因。 Vert.x不是一个框架,它是一个工具包,它不受质疑,而且正在解放。 Vert.x不想让您重新设计整个应用程序以使用它,它只是想让您的生活更轻松。 您可以在Vert.x中编写整个应用程序吗? 当然! 您可以将Vert.x功能添加到现有的Spring / Guice / CDI应用程序中吗? 是的 您可以在现有JavaEE应用程序中使用Vert.x吗? 绝对! 这就是让它变得惊人的原因。

背景

Vert.x诞生于Tim Fox决定他喜欢NodeJS生态系统中正在开发的许多东西,但他不喜欢在V8中进行权衡取舍:单线程,有限的库支持以及JavaScript本身。 Tim着手编写一个对如何使用它以及如何使用它没有质疑的工具箱,他决定在JVM上实现它的最佳位置。 因此,Tim和社区开始着手创建一个事件驱动的,非阻塞的,React性的工具包,该工具包在许多方面都可以反映NodeJS可以完成的工作,而且还利用了JVM内部的强大功能。 Node.x诞生了,后来发展成为Vert.x。

总览

Vert.x旨在实现事件总线,该事件总线使应用程序的不同部分可以以非阻塞/线程安全的方式进行通信。 它的一部分是根据Eralng和Akka展示的Actor方法建模的。 它还旨在充分利用当今的多核处理器和高度并发的编程需求。 因此,默认情况下,所有Vert.x VERTICLES默认都实现为单线程。 与NodeJS不同,Vert.x可以在许多线程中运行许多顶点。 另外,您可以指定某些顶点为“工作”顶点,并且可以是多线程的。 为了给蛋糕锦上添花,Vert.x通过使用Hazelcast对事件总线的多节点群集提供了底层支持。 它继续包含许多其他令人惊奇的功能,这些功能太多了,无法在此处列出,但是您可以在Vert.x官方文档中内容。

关于Vert.x,您需要了解的第一件事是,与NodeJS一样,永远不要阻塞当前线程。 默认情况下,Vert.x中的所有内容都设置为使用回调/未来/承诺。 Vert.x不执行同步操作,而是提供异步方法来执行大多数I / O和处理器密集型操作,这些操作可能会阻塞当前线程。 现在,使用回调可能很丑陋且很痛苦,因此Vert.x可以选择提供基于RxJava的API,该API使用Observer模式实现相同的功能。 最后,Vert.x通过在许多异步API上提供executeBlocking(Function f)方法,可以轻松使用现有的类和方法。 这意味着您可以选择喜欢使用Vert.x的方式,而不是由工具包指示必须如何使用它。

了解Vert.x的第二件事是它由顶点,模块和节点组成。 顶点是Vert.x中最小的逻辑单元,通常由单个类表示。 遵循UNIX Philosophy的原则,顶点应该是简单且具有单一用途的。 一组顶点可以放到一个模块中,该模块通常打包为单个JAR文件。 一个模块代表一组相关的功能,这些功能一起使用时,可以代表整个应用程序,也可以代表较大的分布式应用程序的一部分。 最后,节点是运行一个或多个模块/垂直模块的JVM的单个实例。 由于Vert.x具有从头开始内置的群集功能,因此Vert.x应用程序可以跨越一台计算机或跨多个地理位置的多台计算机跨越节点(尽管延迟可能会掩盖性能)。

示例项目

现在,我最近去过许多聚会和会议,在他们谈论React式编程时,它们向您展示的第一件事就是构建一个聊天室应用程序。 很好,但这并不能真正帮助您完全理解响应式开发的力量。 聊天室应用程序既简单又简单。 我们可以做得更好。 在本教程中,我们将使用旧版Spring应用程序并将其转换为利用Vert.x的优势。 这具有多个目的:表明该工具包易于与现有的Java项目集成,它使我们能够利用可能是生态系统中根深蒂固的现有工具的优势,并且使我们遵循DRY原则 ,因为我们不不必重写大量代码即可获得Vert.x的好处。

我们的旧版Spring应用程序是使用Spring Boot,Spring Data JPA和Spring REST的REST API的简单示例。 源代码可以在“主”分支中找到该处 。 我们还将使用其他分支来演示进展,因此,只要对gitJava 8有一点经验的人都可以轻松进行。 让我们从检查常规Spring应用程序的Spring Configuration类开始。

@SpringBootApplication
@EnableJpaRepositories
@EnableTransactionManagement
@Slf4j
public class Application {public static void main(String[] args) {ApplicationContext ctx = SpringApplication.run(Application.class, args);System.out.println("Let's inspect the beans provided by Spring Boot:");String[] beanNames = ctx.getBeanDefinitionNames();Arrays.sort(beanNames);for (String beanName : beanNames) {System.out.println(beanName);}}@Beanpublic DataSource dataSource() {EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();return builder.setType(EmbeddedDatabaseType.HSQL).build();}@Beanpublic EntityManagerFactory entityManagerFactory() {HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();vendorAdapter.setGenerateDdl(true);LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();factory.setJpaVendorAdapter(vendorAdapter);factory.setPackagesToScan("com.zanclus.data.entities");factory.setDataSource(dataSource());factory.afterPropertiesSet();return factory.getObject();}@Beanpublic PlatformTransactionManager transactionManager(final EntityManagerFactory emf) {final JpaTransactionManager txManager = new JpaTransactionManager();txManager.setEntityManagerFactory(emf);return txManager;}
}

正如您在课程顶部看到的那样,我们有一些非常标准的Spring Boot注释。 你还会看到@ SLF4J批注这是一部分Lombok库,旨在帮助降低锅炉板代码。 我们还有@Bean注释方法,用于提供对JPA EntityManager,TransactionManager和DataSource的访问。 这些项目中的每一个都提供可注入的对象,供其他类使用。 项目中的其余类也类似地简化。 有一个客户 POJO,它是服务中使用的实体类型。 通过Spring Data创建了一个CustomerDAO 。 最后,有一个CustomerEndpoints类,它是JAX-RS注释的REST控制器。

如前所述,这是Spring Boot应用程序中的所有标准票价。 该应用程序的问题在于,在大多数情况下,它的可伸缩性有限。 您可以在Servlet容器中运行此应用程序,也可以在Jetty或Undertow之类的嵌入式服务器中运行该应用程序。 无论哪种方式,每个请求都占用一个线程,因此在等待I / O操作时浪费了资源。

切换到Convert-To-Vert.x-Web分支,我们可以看到Application类发生了一些变化。 现在,我们有了一些新的@Bean批注方法来注入Vertx实例本身,以及ObjectMapper实例(Jackson JSON库的一部分)。 我们还用新的CustomerVerticle替换了CustomerEnpoints类。 几乎所有其他内容都是相同的。

CustomerVerticle类带有@Component注释,这意味着Spring将在启动时实例化该类。 它还具有用@PostConstruct注释的start方法,以便在启动时启动Verticle。 查看代码的实际内容,我们看到Vert.x代码的第一部分: Router

Router类是vertx-web库的一部分,它使我们能够使用流畅的API来定义HTTP URL,方法和标头过滤器以进行请求处理。 将BodyHandler实例添加到默认路由可以处理POST / PUT正文并将其转换为JSON对象,然后Vert.x可以将其作为RoutingContext的一部分进行处理。 Vert.x中的路由顺序可能很重要。 如果定义的路由具有某种形式的全局匹配(*或regex),则除非实现chaining ,否则它可能会吞噬在其后定义的路由的请求。 我们的示例最初显示了3条路线。

@PostConstructpublic void start() throws Exception {Router router = Router.router(vertx);router.route().handler(BodyHandler.create());router.get("/v1/customer/:id").produces("application/json").blockingHandler(this::getCustomerById);router.put("/v1/customer").consumes("application/json").produces("application/json").blockingHandler(this::addCustomer);router.get("/v1/customer").produces("application/json").blockingHandler(this::getAllCustomers);vertx.createHttpServer().requestHandler(router::accept).listen(8080);}

请注意,定义了HTTP方法,定义了“ Accept”标头(通过消耗),定义了“ Content-Type”标头(通过生产)。 我们还看到我们正在通过对blockingHandler方法的调用传递对请求的处理。 Vert.x路由的阻塞处理程序接受RoutingContext对象,因为它是唯一的参数。 RoutingContext保存Vert.x请求对象,响应对象和任何参数/ POST主体数据(例如“:id”)。 您还将看到,我使用方法引用而不是lambda来将逻辑插入blockingHandler(我发现它更具可读性)。 这3条请求路由的每个处理程序都在该类中一个单独的方法中定义。 这些方法基本上只是调用DAO上的方法,根据需要进行序列化或反序列化,设置一些响应头,并通过发送响应来结束请求。 总体而言,非常简单明了。

private void addCustomer(RoutingContext rc) {try {String body = rc.getBodyAsString();Customer customer = mapper.readValue(body, Customer.class);Customer saved = dao.save(customer);if (saved!=null) {rc.response().setStatusMessage("Accepted").setStatusCode(202).end(mapper.writeValueAsString(saved));} else {rc.response().setStatusMessage("Bad Request").setStatusCode(400).end("Bad Request");}} catch (IOException e) {rc.response().setStatusMessage("Server Error").setStatusCode(500).end("Server Error");log.error("Server error", e);}}private void getCustomerById(RoutingContext rc) {log.info("Request for single customer");Long id = Long.parseLong(rc.request().getParam("id"));try {Customer customer = dao.findOne(id);if (customer==null) {rc.response().setStatusMessage("Not Found").setStatusCode(404).end("Not Found");} else {rc.response().setStatusMessage("OK").setStatusCode(200).end(mapper.writeValueAsString(dao.findOne(id)));}} catch (JsonProcessingException jpe) {rc.response().setStatusMessage("Server Error").setStatusCode(500).end("Server Error");log.error("Server error", jpe);}}private void getAllCustomers(RoutingContext rc) {log.info("Request for all customers");List customers = StreamSupport.stream(dao.findAll().spliterator(), false).collect(Collectors.toList());try {rc.response().setStatusMessage("OK").setStatusCode(200).end(mapper.writeValueAsString(customers));} catch (JsonProcessingException jpe) {rc.response().setStatusMessage("Server Error").setStatusCode(500).end("Server Error");log.error("Server error", jpe);}}

您可能会说:“但是,这比我的Spring注释和类还要更多的代码和混乱”。 这可能是正确的,但实际上取决于您如何实现代码。 这只是一个介绍性的示例,因此我使代码非常简单易懂。 我可以使用Vert.x的注释库以类似于JAX-RS的方式实现端点。 此外,我们还获得了可扩展性的巨大改进。 在幕后,Vert.x Web使用Netty进行低级异步I / O操作,从而使我们能够处理更多并发请求(受数据库连接池的大小限制)。

通过使用Vert.x Web库,我们已经对该应用程序的可伸缩性和并发性进行了一些改进,但是通过实现Vert.x EventBus ,我们可以做一些改进。 通过将数据库操作分为Worker Verticles,而不是使用blockingHandler,我们可以更有效地处理请求处理。 这在“ 转换为工作人员垂直”分支中显示。 应用程序类保持不变,但是我们更改了CustomerEndpoints类,并添加了一个名为CustomerWorker的新类。 此外,我们添加了一个名为Spring Vert.x Extension的新库,该库为Vert.x Verticles提供了Spring Dependency Injections支持。 首先查看新的CustomerEndpoints类。

@PostConstructpublic void start() throws Exception {log.info("Successfully create CustomerVerticle");DeploymentOptions deployOpts = new DeploymentOptions().setWorker(true).setMultiThreaded(true).setInstances(4);vertx.deployVerticle("java-spring:com.zanclus.verticles.CustomerWorker", deployOpts, res -> {if (res.succeeded()) {Router router = Router.router(vertx);router.route().handler(BodyHandler.create());final DeliveryOptions opts = new DeliveryOptions().setSendTimeout(2000);router.get("/v1/customer/:id").produces("application/json").handler(rc -> {opts.addHeader("method", "getCustomer").addHeader("id", rc.request().getParam("id"));vertx.eventBus().send("com.zanclus.customer", null, opts, reply -> handleReply(reply, rc));});router.put("/v1/customer").consumes("application/json").produces("application/json").handler(rc -> {opts.addHeader("method", "addCustomer");vertx.eventBus().send("com.zanclus.customer", rc.getBodyAsJson(), opts, reply -> handleReply(reply, rc));});router.get("/v1/customer").produces("application/json").handler(rc -> {opts.addHeader("method", "getAllCustomers");vertx.eventBus().send("com.zanclus.customer", null, opts, reply -> handleReply(reply, rc));});vertx.createHttpServer().requestHandler(router::accept).listen(8080);} else {log.error("Failed to deploy worker verticles.", res.cause());}});}

路由相同,但实现代码不同。 现在,我们不再使用对blockingHandler的调用,而是实现了适当的异步处理程序,该处理程序在事件总线上发送事件。 此Verticle中不再进行任何数据库处理。 我们已将数据库处理移至一个工作线程,该线程具有多个实例,以线程安全的方式并行处理多个请求。 我们还为这些事件的回复时间注册了一个回调,以便我们可以向发出请求的客户端发送适当的响应。 现在,在CustomerWorker Verticle中,我们已经实现了数据库逻辑和错误处理。

@Override
public void start() throws Exception {vertx.eventBus().consumer("com.zanclus.customer").handler(this::handleDatabaseRequest);
}public void handleDatabaseRequest(Message<Object> msg) {String method = msg.headers().get("method");DeliveryOptions opts = new DeliveryOptions();try {String retVal;switch (method) {case "getAllCustomers":retVal = mapper.writeValueAsString(dao.findAll());msg.reply(retVal, opts);break;case "getCustomer":Long id = Long.parseLong(msg.headers().get("id"));retVal = mapper.writeValueAsString(dao.findOne(id));msg.reply(retVal);break;case "addCustomer":retVal = mapper.writeValueAsString(dao.save(mapper.readValue(((JsonObject)msg.body()).encode(), Customer.class)));msg.reply(retVal);break;default:log.error("Invalid method '" + method + "'");opts.addHeader("error", "Invalid method '" + method + "'");msg.fail(1, "Invalid method");}} catch (IOException | NullPointerException e) {log.error("Problem parsing JSON data.", e);msg.fail(2, e.getLocalizedMessage());}
}

CustomerWorker工人垂直服务器在事件总线上注册消费者以获取消息。 代表事件总线上地址的字符串是任意的,但是建议使用反向tld样式的命名结构,以确保地址唯一(“ com.zanclus.customer”)很简单。 每当有新消息发送到该地址时,它将被传递到一个,只有一个工作层。 然后,工作层将调用handleDatabaseRequest来完成数据库工作,JSON序列化和错误处理。

你有它。 您已经看到Vert.x可以集成到旧版应用程序中,以提高并发性和效率,而不必重写整个应用程序。 我们可以使用现有的Google Guice或JavaEE CDI应用程序完成类似的操作。 当我们在Vert.x中尝试添加响应功能时,所有业务逻辑都可能保持相对不变。 下一步由您决定。 接下来的一些想法包括Clustering , WebSockets和ReactiveX sugar的VertxRx 。

翻译自: https://www.javacodegeeks.com/2015/12/reactive-development-using-vert-x.html

vert.x 分布式锁

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

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

相关文章

c语言 char c1,c2; for (c1='0',C语言-5循环结构(PPT)复习课程.ppt

C语言-5循环结构(PPT)复习课程.ppt第五章 循环结构程序设计;课程引入;第五章 循环结构程序设计;5.1 while 语句;例1&#xff1a;求;1. do-while循环语句的形式 do 循环体 while(条件表达式)&#xff1b; ;表达式0&#xff1f;;【例5.3】while和do-while循环的比较。;一般格式&a…

jvm高并发_JVM上的高并发HTTP客户端

jvm高并发HTTP可能是最流行的应用程序级别协议&#xff0c;并且有许多库在网络I / O之上实现它&#xff0c;这是常规I / O的一种特殊&#xff08;面向流&#xff09;情况。 由于所有I / O都有很多共同点1 &#xff0c;所以让我们开始对其进行一些讨论。 我将集中讨论具有大量并…

html双击变成可编辑,jquery 实现双击编辑并保存

jquery 实现双击编辑并保存Jesse2013-12-11 19:47:001153最近在做一个数据修改的例子&#xff0c;一个个点开修改很麻烦&#xff0c;于是就想到ecshop后台里的 只需单击就以编辑了&#xff0c;在网上查阅资料&#xff0c;就想到双击修改&#xff0c;失去鼠标焦点后post执行HTML…

jmeter 采样器作用_实施自定义JMeter采样器

jmeter 采样器作用随着我们采用不同的体系结构和实现方式&#xff0c;对通用压力测试工具的需求不断增长。 关于负载测试&#xff0c; Apache Jmeter是最知名的工具之一。 它支持许多协议&#xff0c;例如ftp http tcp&#xff0c;并且可以轻松地用于分布式测试。 Jmeter还为…

html 闪烁文本,HTML最简单的文字闪烁代码

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼Titlekeyframes blink{0%{opacity: 1;}50%{opacity: 1;}50.01%{opacity: 0;}100%{opacity: 0;}}-webkit-keyframes blink {0% { opacity: 1; }50% { opacity: 1; }50.01% { opacity: 0; }100% { opacity: 0; }}-moz-keyframes blin…

xp系统 javafx_使用JavaFX构建React系统

xp系统 javafxJavaFX是用于在Java中构建图形应用程序的新标准库&#xff0c;但是许多程序员仍然对Swing甚至&#xff08;高音&#xff09;AWT感到困惑。 在Java诞生20年来&#xff0c;发生了很多事情。 两年前&#xff0c;当我开始研究Speedment UI的JavaFX库时&#xff0c;我发…

html手机端图片点击放大缩小快捷键,PS放大缩小图片的快捷键是什么?PS放大缩小图片的操作技巧...

PS放大缩小图片的快捷键是什么&#xff1f;PS怎么放大缩小图片&#xff1f;使用PS处理图片可是个精细的活儿&#xff0c;为了让图片处理得更加完美&#xff0c;我们经常需要将图片放大来处理&#xff0c;修改好之后又要缩小图片看下整体效果&#xff0c;这样来回切换其实挺麻烦…

webstorm html代码提示设置,Webstorm设置代码提示

下载路径&#xff1a; https://github.com/virtoolswebplayer/ReactNative-LiveTemplate本插件可以配合Webstorm设置代码提示。Mac下安装Webstorm2016.1为例安装路径在终端&#xff1a;$ cd ~/Library/Preferences/$ ls找到Webstorm版本$ open WebStorm2016.1先将ReactNative.x…

滑动拼图验证码操作步骤:_拼图项目:一个不完整的难题

滑动拼图验证码操作步骤&#xff1a;马克雷因霍尔德&#xff08;Mark Reinhold&#xff09;最近提议延迟Java 9&#xff0c;以花更多的时间完成项目Jigsaw&#xff0c;这是即将发布的版本的主要功能。 虽然这个决定肯定会使Java的厄运论者重回舞台&#xff0c;但我个人感到很轻…

document中输出html字符串流,HTML DOMDocument从段落后面的标签中获取字符串

我想解析html文档。我需要h2之后所有p的内容。要解析的html :(示例)Lorem ipsumLorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridic…

arcgis adf数据_使用ADF列表视图的主从数据

arcgis adf数据从UI角度来看&#xff0c;最近ADF Faces 表组件不再被认为很酷。 对于显示数据集合&#xff0c; 列表视图今天应该很酷。 这并不意味着我们根本不应该使用af&#xff1a;table 。 在某些情况下&#xff08;经常是:)&#xff09;&#xff0c;表比列表视图更适合。…

jmeter添加html,Jmeter 报告可视化 —— 配置生成测试报告仪表板,Jmeter + Jenkins 自动化构建生成 HTML 报告...

目录一、jmeter报告仪表板相关信息二、文件修改说明三、jmeter.properties文件配置四、user.properties文件配置五、新建jtl报告目录六、复制jmeter.properties文件并重命名七、写批处理bat文件八、准备jmeter测试计划脚本九、本地调试bat文件十、Jenkins自动化构建一、jmeter报…

gradle java_Java EE,Gradle和集成测试

gradle java在过去的几年中&#xff0c;Apache Maven已成为Java和Java EE项目的事实上的构建工具。 但是从两年前开始&#xff0c; Gradle便获得了越来越多的用户。 在我之前的文章&#xff08; http://www.lordofthejars.com/2015/10/gradle-and-java-ee.html &#xff09;之后…

javafx 内存占用_JavaFX:TouchGesture内存泄漏?

javafx 内存占用在我的一个项目中&#xff0c;最近几天我在与内存泄漏作斗争&#xff08;是……“耦合”&#xff09;&#xff0c;我得出的结论是可能存在与触摸/滚动手势有关的问题。 在下面的示例中&#xff0c;我有两个按钮。 第一个创建具有一千行的列表视图&#xff0c;第…

手机单选按钮 html5,@html剃刀单选按钮mvc5(@html razor radio buttons mvc5)

这里是我的视图模型public class UserResponseModel{public string QuestionId { get; set;}public string QuestionText { get; set; }public bool IsChecked { get; set; }}所以&#xff0c;对于这个复选框精美作品for (var i 0; i < Model.UserResponses.Count; i){Html…

cucumber jvm_用Cucumber JVM编写BDD测试

cucumber jvmCucumber JVM是编写BDD测试的出色工具。在本文中&#xff0c;我想对Cucumber JVM的BDD进行介绍。 让我们开始吧… 什么是BDD&#xff1f; 简而言之&#xff0c;BDD试图解决“通过示例理解需求”的问题 BDD工具 有许多可用于BDD的工具&#xff0c;有趣的是&#…

计算机网络英文介绍,计算机网络英文自我介绍

计算机网络英文自我介绍It’s my pleasure to introduce myself to you here. My name is XX, Icome from XX which is a beautiful city. And I am a candidate forthe position of Sales Representative. 公务员面试自我介绍I attended Nantong University in 2003. My major…

模拟模型学习 几何布朗运动_Java的几何布朗运动

模拟模型学习 几何布朗运动维纳过程是一个连续时间的随机过程&#xff0c;以纪念诺伯特维纳。 通常用于用随机成分表示噪音或财务状况。 可以计算几何布朗运动以可视化某些界限&#xff08;以分位数表示&#xff09;以暗示绝对范围。 为了进行计算&#xff0c;需要以下参数&am…

计算机网络基础 第4章 龚娟,计算机网络基础 人民邮电 龚娟 第4章习题答案

1&#xff0e;关于IPv4地址的说法&#xff0c;错误的是( C )。A&#xff0e;IP地址是由网络地址和主机地址两部分组成 B&#xff0e;网络中的每台主机分配了唯一的IP地址 C&#xff0e;IP地址只有三类&#xff1a;A&#xff0c;B&#xff0c;CD&#xff0e;随着网络主机的增多&…

动态调整线程池_调整线程池的重要性

动态调整线程池无论您是否知道&#xff0c;您的Java Web应用程序很可能都使用线程池来处理传入的请求。 这是许多人忽略的实现细节&#xff0c;但是迟早您需要了解如何使用该池以及如何为您的应用程序正确调整池。 本文旨在说明线程模型&#xff0c;线程池是什么以及正确配置线…