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开发的三种方式
使用现成的Web容器,如Tomcat,这是使用最多的一种,也是很多的Java开发者可能最先想到的,只要下载一个Tomcat,再编写个web项目就可以对外提供Web服务。这种方式我们完全不需要考虑线程的交互,不需要考虑网络协议,只需要关注业务逻辑,可以说是一种全包的形式。
使用Java原生的Socket或者NIO来实现,但这种方式比较复杂,对编程功底要求最高,并且要求开发者对HTTP协议必须有深入的理解。这种实现方式完全需要手动处理,很少会使用这种方式来实现HTTPServer,可以说这是最为原始形式。
介于全包和原始形式之间,就是用第三方的框架来实现,比如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非常熟悉的朋友,看这里应该会有种似曾相识的感觉。
上图中的监听组件、路由组件都可以直接放到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下]。下面简单列出实现的步骤:
创建一个Maven项目,并配置依赖的包。(这里仅仅需要引入vertx-core的包即可)
创建一个核心类,创建main方法,直接在main方法中编写代码即可(后期会进行改造)
直接运行核心类,并通过浏览器访问
下面是具体的代码
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。
对比两者可以发现,实际上就是简化了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中运行,实现步骤如下:
创建一个类,继承AbstractVerticle类
重写start方法和stop方法,在start方法中处理业务逻辑,stop方法中释放资源
在main方法中部署Verticle模块
启动服务,并通过浏览器进行访问
代码如下:
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());
}
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服务-原理篇的主要内容,如果未能解决你的问题,请参考以下文章