您的位置:首页 > 移动开发 > Android开发

Jetty系列: 01- 基本使用和简单介绍

2017-11-15 14:57 555 查看

为什么要写这个系列

故事的开头要从博主两年前做的一个需求开始. 当时我在公司的Android项目组做开发, app要加一个免流量分享应用的功能. 应用场景是这样: 我手机上装了一个app, 现在要传给你, 不耗费双方的上网流量. 怎么做呢? 过程是这样:

我在手机上开一个WiFi热点, app内部起一个web服务, 把web服务的地址生成二维码.

你扫这个二维码, 得到一个网址, 如:http://192.168.x.xx:8080/

你在手机浏览器里打开这个网址, 看到的是一个介绍页面, 点击一个免流量下载按钮, 访问链接是:http://192.168.x.xx:8080/download

我这边app内部的web服务器将apk文件通过http发送给你, 对你来说, 跟平时在网页上下载是一样的, 下载完成后, 直接安装. 整个过程不访问外网, 所有通信都通过我的WiFi热点完成, 达到免流量的目的.

当时从技术上来拆分, 主要有以下三点:

WiFi热点的控制 -> 通过系统api调用可以轻松完成

二维码生成 -> 通过zxing库可以做到

在手机里起web服务 -> 看起来有点麻烦

http这一块Android的客户端支持是很完善的, 像apache的HttpClient, java自带的UrlConnection都可以用, 但对于服务器这一块, 还真没接触过, 毕竟 像Tomcat, nginx这种web服务器一般来说都部署在专用服务器主机上的. 这该咋办呢?

基于当时的认知情况, 博主采用了一种最原始的方法: 基于Java的原生socket, 手动写一个简单的web服务器. 大体实现如下:

1.绑定tcp socket到8080端口, 接受连接请求

2. 收到连接请求后, 读取客户端发来的数据

3. 按行解析这些数据, 分析Request-Line, 得到访问的路径, 如果是”/”, 则读取index.html文件, 写入连接socket. 当然了, 在写文件数据前, 需要按照http规范发送Response-Header, 像Content-Length, Content-Type这些字段; 如果是”/download”, 则按照文件的格式发送Response-Header, 跟上apk文件的数据; 其他路径就直接返回404错误.

最后按这种方式实现了目标功能. 但是一眼看来这样实现是有缺点的, 稍微复杂一点的功能都要手动在这个基础上添加, 而很多功能其实都是在HTTP规范里面定义好的, 只要是一个规范的http服务器, 都会实现这些功能, 手动写服务器其实是重复造轮子的动作. 当时在想, 要是有一个可以方便嵌入到手机的web服务器该多好啊!

后来, 由于博主的兴趣在服务端, 正好公司有这个契机, 我就转去做服务器了. Android端也有一部分工作, 主要是给业务团队提供SDK, 封装一部分JNI.

又过了一段时间, 博主遇到一个需求, 手机客户端的日志, 存储到后台做分析. 这里又遇到http服务器了, 当然这次运行的目标机器是服务器, 可选择的就很多了, 当时的决策如下:

nginx - 一般用来做负载均衡, 或者处理一些静态请求, 如果要做业务处理的话, 需要写C来扩展, 不是很方便.

Tomcat - 能完成需求, 但是太重了. 跟当时的app需求一样, 我只要轻量的http功能, 最好是集成到应用代码里的

nginx+php, 可以实现, 不过在接受完http请求后, 还需要和其他java组件做交互, 这点不是很方便; 其次, 博主对php不熟悉.

Jetty, 当时查了一些资料后发现了它, 可以内嵌到应用内部, 并且性能也不错, 于是决定就它了.

Netty, 高性能的java异步IO框架. 说实话当时博主以为Jetty的底层用的就是Netty框架呢, 而且当时看到Jetty的http服务器的例子就几行代码(后面可以看到), 就决定用了.

有的同学一定会疑问怎么没使用Netty呢, 至少我身边的人对Netty提到的机会比jetty是高很多的. 老实说, 如果当时没有误以为Jetty底层就是Netty的话, 我当时可能会考虑使用Netty来做开发. 不过到现在这个时候来说, 我觉得一点也不后悔. 主要有以下几点:

Jetty的上手代码非常简洁, 好用的东西就是要用起来方便直接的; Netty的例子代码也不多, 但是会看到很多陌生的概念, Future, Channel等, 对博主来说, 除非对一个东西对原理了解透彻, 不然基本是不会放心用的. 而Netty的这些概念对当是的博主造成了一定的思想压力.

最近仔细看了Jetty的部分实现代码, 结构还是非常清晰的. Netty非常好, Jetty也不错, 所有的功能无非都是基于原始的操作系统Socket和线程概念组合起来的, 不一定非要用最好的, 了解你所用的组件, 发生问题的时候快速定位找到问题, 才是最重要的.

说了这么多, 其实是因为博主和大多数工程师一样, 都有些强迫症情节, 用东西都追求最好的, 性能要最高的. 这在很多时候其实是不好的, 高性能的东西, 可能用起来不顺手, 或者开发和部署需要比较多的时间, 或者发挥高性能的前提是要对它有足够的认知. 作为工程师的天职, 是为解决生活中的问题而存在的. 一味地追求高端, 只会迷失在茫茫多的组件当中. 而从这么多功能相近的组件同时存在也可以看出, 每个组件都有自己的立足之地, 一定是因为它很好的满足了一部分人的需求. 选择合适自己的, 了解它, 改进它!!!

Jetty简单介绍

Jetty是Eclipse基金会下面的一个开源项目, 是一个Web服务器和Servlet容器, 同时支持HTTP/2, WebSocket, OSGi, JMX, JNDI, JAAS功能. Jetty可以作为web服务器非常容易的嵌入到应用代码中, 包括Android的app.

Jetty除了嵌入到应用代码中外, 也可以像Tomcat那样独立运行, 通过部署WAR包的方式提供服务. 理论上来说, Tomcat下面运行的WAR包可以直接在Jetty下运行, 这一点我没有验证过. 有需要的同学可以自行验证. 接下来的博客中主要介绍嵌入运行方式.

接下来通过一个简单的例子来看看Jetty是如何开发的.

package com.lqp.test;

import org.apache.logging.log4j.LogManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;

public class TestJettyServer {

public static void main(String[] args) {
Server server = new Server(8080);

ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);

ContextHandler resHanler = new ContextHandler();
resHanler.setHandler(resource_handler);
resHanler.setResourceBase(".");
resHanler.setContextPath("/");

server.setHandler(resHanler);
try {
server.start();
} catch (Exception e) {
LogManager.getLogger().catching(e);
}
}
}


启动一个JettyWeb服务器就是这么简单. 启动后, 就可以在浏览器里浏览和查看当前目录下的文件了. 效果如下图:



Handler是Jetty服务器的业务功能实现地, 如果要扩展web服务器的功能, 只需要添加自己实现的handler就行, 还是很容易理解的.

如何引用jetty的jar包

下载jar包, 添加jar引用, 这里是下载地址

Maven依赖引用, 推荐这种方式.

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.2.v20170220</version>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.2.v20170220</version>
</dependency>


后面的系列中, 主要围绕9.4.2.v20170220版本的代码来做分析.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android jetty web服务