Vert.x 创建HTTP服务-原理篇

Posted 闲话Java

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vert.x 创建HTTP服务-原理篇相关的知识,希望对你有一定的参考价值。

哈喽,大家好,欢迎阅读闲话Java的Vert.x部分,本篇是闲话Vert.x的第二期,《Vert.x创建HTTP服务》。本期由闲话哥带您从头创建一个基于Vert.x的HTTP服务,并能对外提供服务。

Vert.x创建HTTP服务主要分为原理篇和实战篇,原理篇主要论述Web开发的理论基础,并快速体验Vert.x开发HTTP服务。实战篇来完成一个对外提供天气服务的案例。

后续所使用的代码均开源在:https://github.com/happy-fly/wxcode


理解Web开发的本质

Vert.x的Web开发和传统的Web开发差别比较大,为了能够帮助开发者更好的理解Vert.x的Web开发,我们先从Web开发的本质来谈起。

Web开发的本质是遵循HTTP规范,接收HTTP客户端的请求,经过服务器处理后把结果响应给HTTP客户端,底层就是基于HTTP的网络通信。

作为普通的Java开发者,可能很大时间都在做Web应用的开发,通过Web开发的本质,我梳理了三种Web开发的方法。

Web开发的三种方式

  1. 使用现成的Web容器,如Tomcat,这是使用最多的一种,也是很多的Java开发者可能最先想到的,只要下载一个Tomcat,再编写个web项目就可以对外提供Web服务。这种方式我们完全不需要考虑线程的交互,不需要考虑网络协议,只需要关注业务逻辑,可以说是一种全包的形式。

  2. 使用Java原生的Socket或者NIO来实现,但这种方式比较复杂,对编程功底要求最高,并且要求开发者对HTTP协议必须有深入的理解。这种实现方式完全需要手动处理,很少会使用这种方式来实现HTTPServer,可以说这是最为原始形式。

  3. 介于全包和原始形式之间,就是用第三方的框架来实现,比如Vertx或者偏底层的Netty。你可以利用框架封装的API简单的创建一个HttpServer,并不需要关注底层的通信协议。这种方式更为灵活,一般来讲性能也更高,并且不依赖中间件。

Vert.x开发Web服务就是这里所说的第三种方式。对于第二种方式,不在我们讨论范围之内,也极少有人使用第二种方式做web开发。那么我们就来比对下第一种方式和第三种方式。

这里称第一种方式为传统Web开发,第三种方式为Vert.x的web开发。


传统Web开发

传统的Java Web开发本质上就是遵循J2EE的Servlet规范来编写代码。然而,Servlet仅提供业务逻辑实现,并不考虑网络通信。网络通信依赖于Web容器提供。我们编写的Servlet代码需要部署到Web容器中才能运行。

简单说,传统的Web开发,需要开发后将编译后的字节码打包放到Web容器(如tomcat)中运行。


基于Vert.x的web开发

Vert.x底层通信框架依赖于Netty,并在Netty的基础上封装了对Http、TCP等协议便于操作的API,因此可以非常方便的进行Web开发。

说白了,Vert.x和传统开发不同的是,Vert.x不依赖容器,自己就是容器,自己启动后就是一个HTTPServer。

Vert.x和node的机制非常像,如果对node非常熟悉的朋友,看这里应该会有种似曾相识的感觉。

Vert.x 创建HTTP服务-原理篇

上图中的监听组件、路由组件都可以直接放到main方法中,模块业务的实现也可以放到main方法中。也就是说,一个main方法,直接运行,就可以对外提供HTTP服务,并且不依赖任何Web容器。


Vert.x和传统Web开发对比

传统Web开发的优势

  • 只需要关注业务逻辑实现,不需要关注底层的网络通信

  • 技术体系非常成熟,除了传统的Servlet,还有类似Struts、SpringMVC的框架,对于开发来讲更容易上手。

  • 低的学习成本。这里不是针对开发者学习的成本,而是针对企业用人的成本。绝大部分的开发者是可以不需要培训就可以上手的。

传统Web开发的劣势

  • 依赖Web容器,商业Web容器费用非常高(当然也提供更好的服务,也不能算劣势)

  • 一般是同步IO模型,每个请求开辟一个物理线程来提供服务,这样会降低系统的性能,导致大量的线程可能处于Wait状态。

  • Web容器是通用的项目,可定制性不强。

  • Web容器可能会存在bug。

Vert.x开发的优势

  • 不依赖Web容器,完全灵活,组件都可以自定义,享受写Web容器的快感。

  • 运行简单,直接运行main方法,或者直接打成可运行的jar即可。

  • 基于Netty,可以处理高并发的请求。

  • 不仅仅实现HTTP服务,还可以实现TCP服务。

Vert.x开发的劣势

  • 灵活带来更复杂的编码

  • 全异步开发,对编程功底要求更高,调试日志记录等有复杂的挑战


实战

下面简单的来实现一个HttpServer,通过浏览器访问这个HttpServer能够在浏览器上显示HelloWorld[后续用到的代码均开源到:https://github.com/happy-fly/wxcode下]。下面简单列出实现的步骤:

  1. 创建一个Maven项目,并配置依赖的包。(这里仅仅需要引入vertx-core的包即可)

  2. 创建一个核心类,创建main方法,直接在main方法中编写代码即可(后期会进行改造)

  3. 直接运行核心类,并通过浏览器访问

下面是具体的代码

pom文件

<properties> <vertx.version>4.0.0</vertx.version></properties>
<dependencies> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-core</artifactId> <version>${vertx.version}</version> </dependency></dependencies>

创建核心类MyHttpServer

 
   
   
 
package com.kgh.wxcode.vertx.http;
import io.vertx.core.Vertx;import io.vertx.core.http.HttpServer;import io.vertx.core.http.HttpServerResponse;
/** * 基础的HttpServer * * 1、创建Vertx实例 * 2、创建HttpServer实例 * 3、设置监听的端口号 * 4、监听客户端请求,并进行处理 * * @author kgh */public class BaseHttpServer_main {  public static void main(String[] args) {    // 创建Vertx实例    Vertx vertx = Vertx.vertx();    // 创建HttpServer实例    HttpServer httpServer = vertx.createHttpServer();    // 处理客户端请求    httpServer.requestHandler(request -> {        // 获取到response对象        HttpServerResponse response = request.response();
        // 设置响应头        response.putHeader("Content-type""text/html;charset=utf-8");
        // 响应数据        response.end("HELLO WORLD");      });
// 指定监听端口      httpServer.listen(80);  }}

码非常简单,首先获取到Vertx对象,然后通过vertx对象创建Http服务,监听Http请求并进行处理。

JDK8特性解读

虽然Java已经发布了JDK15,但很多的开发者对JDK8的特性还有些不熟悉,这里简单对用到的JDK8中的特性进行一个简单的说明。


第一个是Vertx.vertx()方法,通过查看代码可以知道Vertx是一个接口,按照我们以前的逻辑,方法实现是不能写在接口中的,在JDK8中增加了静态方法和默认方法。


第二个是【->符号,这也是一个新特性,可能看起来比较难懂,可以类比javascript来理解,JavaScript中有很多这样的写法。我们可以看到,这个方法实际上是接收一个Handle接口,Handle接口中有一个抽象方法 public void handle(HttpServerRequest request) ,这个方法有一个参数 HttpServerRequest。


Vert.x 创建HTTP服务-原理篇

对比两者可以发现,实际上就是简化了new 子类,简化了重写方法,直接把方法的参数后跟->{方法体}来解决。这样写起来是非常方便的。但是这种写法一个接口中只能定义一个抽象方法。这种接口一般会打上@FunctionalInterface注解。


上面那段代码是直接写到main方法中的,可以直接运行即可。监听的是80端口,在启动的过程中,要保证80端口不被占用。启动成功之后可以直接通过浏览器访问。

浏览器访问 localhost

到这里,一个简单的Vertx程序就写完了。


代码改进

在上面演示的创建HttpServer的方式我们会发现有一个很大的问题,就是所有的代码都写在main方法中,这样显然是不好的。Vert.x推荐的写法是为每一个应用创建一个Verticle,也就是Vert.x的模块,然后通过Vertx核心接口,部署Verticle模块。多个Verticle模块之间可以通过EventBus进行相互调用。

这里提到了Verticle、EventBus等,这些都是Vert.x中一些非常重要的概念。Verticle可以简单的理解为继承了AbstractVerticle的类都是一个Verticle,每个Verticle可以单独部署或者单独运行。EventBus看不见,摸不着,可以简单的理解为,各Verticle模块之间通信的桥梁。

下面我们就创建一个HttpServer的Verticle模块,并部署到Vertx中运行,实现步骤如下:

  1. 创建一个类,继承AbstractVerticle类

  2. 重写start方法和stop方法,在start方法中处理业务逻辑,stop方法中释放资源

  3. 在main方法中部署Verticle模块

  4. 启动服务,并通过浏览器进行访问

代码如下:

package com.kgh.wxcode.vertx.http;
import io.vertx.core.AbstractVerticle;import io.vertx.core.Vertx;import io.vertx.core.http.HttpServer;import io.vertx.core.http.HttpServerResponse;
/** * 最基础的HTTP服务 * * 1、继承AbstractVerticle * 2、重写start方法,执行逻辑在start方法中实现 * 3、部署Verticle * * @author kgh */public class BaseHttpServer extends AbstractVerticle {
public static void main(String[] args) { // 部署Verticle Vertx.vertx().deployVerticle(new BaseHttpServer()); }
@Override public void start() throws Exception { HttpServer httpServer = this.getVertx().createHttpServer(); httpServer.requestHandler(request -> { // 获取到response对象 HttpServerResponse response = request.response();
// 设置响应头 response.putHeader("Content-type", "text/html;charset=utf-8");
// 响应数据 response.end("SUCCESS"); });
// 指定监听80端口 httpServer.listen(80); }}

上面代码比较简单,start方法的实现和第一个演示中的main方法代码非常相似,start方法中之所以可以直接使用vertx这个变量,是因为继承了AbstractVerticle这个类,在这个类里有一个protected类型的Vertx变量。

另外在main方法中,获取Vertx实例是通过Vertx.vertx()方法,在Vertx中,这种方式非常常见。

这种编码方式是Vertx官方所支持的方式,后面的案例都会通过这种方式来进行编写。

到这里,我们了解了Vert.x创建HttpServer的API,我们发现,Vertx的API还是非常简洁,好用的。后续在开发的过程中,会越发的感觉到Vert.x的代码的简洁性和一致性。

当然了,如果要真正的实现一个HttpServer,还需要更多的东西,比如路由,Session,Rest接口开发,模板,WebSocket等等,下一期,我会带大家实现一个对外提供天气服务的Web应用,让我们来感受下Vert.x开发Web应用的魅力。


以上是关于Vert.x 创建HTTP服务-原理篇的主要内容,如果未能解决你的问题,请参考以下文章

Vert.x简介原理与HelloWorld

Vert.x 3 和微服务

基于大数据的Uber数据实时监控(Prat 3:使用Vert.x的实时仪表盘)

Vert.x学习之 Web Client

vert.x学习,动态模板与静态文件的结合

Vert.x初体验