1嵌入式jetty简介
在介绍嵌入式jetty之前,首先介绍一下jetty。
Jetty 是一个开源的servlet容器,它为基于Java的web内容,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供网络和Web连接。
Jetty主要有以下特性:
易用性
易用性是 Jetty 设计的基本原则,易用性主要体现在以下几个方面:
通过 XML 或者 API 来对Jetty进行配置;默认配置可以满足大部分的需求;将 Jetty 嵌入到应用程序当中只需要非常少的代码;
可扩展性
在使用了 Ajax 的 Web 2.0 的应用程序中,每个连接需要保持更长的时间,这样线程和内存的消耗量会急剧的增加。这就使得我们担心整个程序会因为单个组件陷入瓶颈而影响整个程序的性能。但是有了 Jetty:即使在有大量服务请求的情况下,系统的性能也能保持在一个可以接受的状态。利用Continuation 机制来处理大量的用户请求以及时间比较长的连接。 另外 Jetty 设计了非常良好的接口,因此在 Jetty 的某种实现无法满足用户的需要时,用户可以非常方便地对 Jetty 的某些实现进行修改,使得 Jetty 适用于特殊的应用程序的需求。
易嵌入性
Jetty 设计之初就是作为一个优秀的组件来设计的,这也就意味着 Jetty 可以非常容易的嵌入到应用程序当中而不需要程序为了使用 Jetty 做修改。从某种程度上,你也可以把 Jetty 理解为一个嵌入式的Web服务器。
Jetty有一个口号:不要把你的应用部署到Jetty中,把Jetty部署到你的应用中。Jetty可以在Java应用程序中向其他POJO一样被实例化,换句话说,以嵌入式的模式运行Jetty是指将Http模块放入你的应用程序中,而非部署你的程序到一个HTTP服务器。这就是所谓的嵌入式jetty。
JETTY嵌入式Web容器体积小,启动速度快,性能好,免费开源,是一款很适合开发调试和简单演示的轻量级Web容器。而且它的嵌入式的特点,使得开发者可以直接将容器的操作包含在程序逻辑里,得以摆脱TOMCAT,JBOSS等独立容器带来的安装,维护,部署等一系列令人头疼的问题。
2 嵌入式jetty的HTTP实现
2.1 简单HTTP实现
2.1.1 HTTP SERVER端实现
2.1.1.1 HTTP SERVER端实现概述
在代码中嵌入一个Jetty server,通常需要以下步骤:
l 创建Server
l 添加/配置Connectors
l 添加/配置Handlers
l 添加/配置Servlets/Webapps到Handlers
l 启动服务器并join
2.1.1.2 创建一个Server
Jetty的Service对象就是Jetty容器,实例化出这样一个对象就产生了一个容器。
Server server = new Server();
可以为Server设置线程池,如果不设置Server处理请求默认为阻塞状态.
server.setThreadPool(newExecutorThreadPool(25, 50, 30000));
简单示例如下:
public class SimplestServer
{
public static void main(String[] args) throwsException
{
Serverserver = new Server(8080);
server.start();
server.join();
}
}
2.1.1.3 配置Connectors
创建Server实例时传入了一个端口号参数,程序内部会创建一个Connector的默认实例,在指定的端口上监听请求。然而,通常嵌入式的Jetty需要为一个Server实例显式地实例化并配置一个或多个Connector。
//实例化
SelectChannelConnector connector = newSelectChannelConnector();
//设置主机地址
connector.setHost("localhost");
//设置端口号
connector.setPort(40404);
/*设置最大空闲时间,最大空闲时间在以下几种情况下应用:
1) 等待一个连接的新的请求时;
2) 读取请求的头信息和内容时;
3) 写响应的头信息和内容时;*/
connector.setMaxIdleTime(30000);
/*为connector设置线程池,如果不设置connector处理请求默认为阻塞状态。如上所示Sever中也有个setThreadPool方法,我觉得如果通过connector进行设置后,会覆盖Sever中的设置。
ExecutorThreadPool构造方法的三个参数分别为:
1) corePoolSize:线程池的基本大小也就是线程池的目标大小,即在没有任务执行时线程池的大小( 线程池维护线程的最少数量);
2) maximunPoolSize:线程池最大大小,表示可同时活动的线程数量的上限;
3) keepAliveTime:存活时间,单位为毫秒,如果某个线程的空闲时间超过了存活时间,那么将被标记为可回收的;
*/
connector.setThreadPool(new ExecutorThreadPool(25, 50,30000));
/*设置这个Server的连接(可以是多个),每个连接有对应的线程池和Handler*/
server.setConnectors(newConnector[] { connector });
嵌入式Jetty服务器的实现的步骤通常为:
2.1.1.4 编写Handlers
为了对每个请求作出相应,Jetty要求为Server设定Handler,Handler可以处理:
1) 检查或修改Http请求
2) 生成完整的Http响应
3) 调用另一个Handler
4) 选择一个或多个Handlers调用
下述代码显示了一个简单HelloHandler的实现:
public class HelloHandler extends AbstractHandler
{
public void handle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response)
throwsIOException, ServletException
{
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
baseRequest.setHandled(true);
response.getWriter().println("<h1>Hello World</h1>");
}
}
handle为AbstractHandler抽象类中定义的抽象方法,我们对请求的处理操作主要通过此方法来完成,handle中参数包括:
target:请求的目标,可以是一个URI或者一个命名dispatcher中的名字。
baseRequest:Jetty的可变请求对象,总是unwrapped。
Request:不变的请求对象,可能会被过滤器或servlet包装
Response:响应,可能会被过滤器或servlet包装
hadler设定响应的状态,内容类型,并在使用writer生成响应体之前标记请求为已处理。
下面是运行Jetty server 使用HelloWorld Handler的例子:
publicstaticvoid main(String[]args)throwsException
{
Server server=new Server(8080);
server.setHandler(new HelloHandler());
server.start();
server.join();
}
2.1.1.5 启动Server并join
server.start();
server.join();
至此,嵌入式jetty的Server端基本编写方式已经完成,然而复杂的请求是建立在很多Handlers的基础上的。下面将详细介绍Handlers的其他内容。
2.1.1.6 理解Handler的几个重要概念
复杂的请求处理通常是建立在多个Handler以不同的方式进行组合上的。
Handler Collection: 维护一个handlers的集合,顺序调用每一个handler。
Handler List:维护一个handlers的集合,依次执行每个handler直到发生异常,或者响应被提交,或者request.isHandled()返回true。
Handler Wrapper:handler的基类,在面向方面编程中能够很好地把一系列处理操作联系在一起。例如,一个标准的Web应用程序是由一连串的context,session,security和servlet处理程序进行执行的。
Context Handler Collection:ContextHandler Collection利用URI最长的前缀来选择特定的context,即拥有相同的URI最长的前缀的context属于同一个ContextHandler Collection。
2.1.1.7 配置文件服务器
下面的代码使用HandlerList来组合ResourceHandler 和DefaultHandler,其中ResourceHandler可以用于处理当前目录下的静态内容:
public class FileServer
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(8080);
server.addConnector(connector);
ResourceHandler resource_handler = new ResourceHandler();
resource_handler.setDirectoriesListed(true);
resource_handler.setWelcomeFiles(new String[]{ "index.html" });
resource_handler.setResourceBase(".");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { resource_handler, new DefaultHandler() });
server.setHandler(handlers);
server.start();
server.join();
}
}
HandlerList包括ResourceHandler和DefaultHandler,后者主要用于当请求不匹配静态资源时返回404错误页面,在本例中即如果没发现文件index.html,则请求转向DefaultHandler,返回404错误页面。
2.1.1.8 设置Contexts
ContextHandler 是一个HandlerWrapper,它只响应特定URL的请求。请求不匹配则不予以处理。请求匹配则执行对应的处理程序。
下面是一个使用例子:
public class OneContext
{
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
ContextHandler context = new ContextHandler();
context.setContextPath("/hello");
context.setResourceBase(".");
context.setClassLoader(Thread.currentThread().getContextClassLoader());
server.setHandler(context);