1.Jetty简介

1.1 什么是Jetty

Jetty是一个提供 HTP服务器、HTTP客户端和javax.servlet容器的开源项目。

Jetty9 是Jetty的最近一个版本且比之前的版本有很大的改进,其中一个改进是Jetty所有特性已经体现在Jetty9的文档里。

历史 :

Jetty有一个口号:不要把应用部署到Jetty上,要把Jetty部署到你的应用里。这句话的意思是把应用打成一个war包部署到Jetty上,不如将Jetty作为应用的一个组件,它可以实例化并像POJO一样。换种说法,在嵌入式模块中运行Jetty意味着把HTTP模块放到你的应用里,这种方法比把你的应用放到一个HTTP服务器里要好。

1.2 概述

本教程中嵌入一个Jetty的典型步骤如下:

  • 创建一个server实例
  • 新增/配置连接
  • 新增/配置处理程序,或者Contexts,或者Servlets
  • 启动Server
  • 等待连接或者在当前线程上做一些其他的事

2. 嵌入式Jetty 使用案例:

2.1 创建一个 server 实例

下面的代码实例化并运行了一个Jetty Server

import org.eclipse.jetty.server.Server;/*** <pre>*     一个简单的 jetty 服务* </pre>** @author saligia* @date 17-10-10*/
public class MyServer {public static void main(String [] args) throws Exception {Server server = new Server(8080);  // 创建一个 jetty 服务server.start();server.dumpStdErr();server.join();}
}

在8080端口运行了一个HTTP服务,因为没有处理程序,所以这不是一个有效的server,所有请求将会返回404错误信息。

2.2 使用处理器处理请求

为了针对请求产生一个相应,Jetty要求用户为服务创建一个处理请求的处理器,一个处理器可以做的工作有:

  • 检测或修改一个请求
  • 一个完整的HTTP响应
  • 处理转发(详见:HandlerWrapper)
  • 处理转发到多个其它处理器上(详见:HandlerCollection)

带有处理器的HelloWorld

接下来的代码HelloHandler.java,表示一个简单的处理程序

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;/*** <pre>* </pre>** @author saligia* @date 17-10-10*/
public class HelloWorldHandle extends AbstractHandler {/*** <pre>* </pre>** @author* @param target              - 目标请求,可以是一个URI或者是一个转发到这的处理器的名字* @param request             - Jetty自己的没有被包装的请求,一个可变的Jetty请求对象* @param httpServletRequest  - 被filter或者servlet包装的请求,一个不可变的Jetty请求对象* @param httpServletResponse - 响应,可能被filter或者servlet包装过* @return*/public void handle(String target, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException {System.out.println("target  :" + target);System.out.println("request : " + request.getRequestURI());System.out.println("requestServ : " + httpServletRequest.getRequestURI());httpServletResponse.setContentType("text/html; charset=utf-8");httpServletResponse.setStatus(HttpServletResponse.SC_OK);PrintWriter out = httpServletResponse.getWriter();out.println("<h1>Hello world</hello>");request.setHandled(true);}
}

运行 Hello world 代码 :

import org.eclipse.jetty.server.Server;/*** <pre>*     一个简单的 jetty 服务* </pre>** @author saligia* @date 17-10-10*/
public class MyServer {public static void main(String [] args) throws Exception {Server server = new Server(8080);  // 创建一个 jetty 服务server.setHandler(new HelloWorldHandle());server.start();server.join();}
}

一个或多个处理器将处理Jetty所有的请求。一些处理器会转发请求到其他处理器(例如: ContextHandlerCollection 会根据路径选择匹配的ContextHandler),另一些将根据逻辑判断来生成相应的响应(例如:ServletHandler 将把request转发到servlet),还有的处理器将处理和请求无关的操作(例如:RequestLogHandler 或者StatisticsHandler)。

后面的章节将介绍如何在切面调用一个处理器,你可以到org.eclipse.jetty.server.handler 包下看看当前可用的处理器。

2.4 处理器的集合以及封装 :

复杂的请求可以由多个处理器来完成,你可以通过不同的方式把它们结合起来,Jetty有几个 HandlerContainer 接口的实现:

package org.eclipse.jetty.server;import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.LifeCycle;@ManagedObject("Handler of Multiple Handlers")
public interface HandlerContainer extends LifeCycle {@ManagedAttribute("handlers in this container")Handler[] getHandlers();@ManagedAttribute("all contained handlers")Handler[] getChildHandlers();Handler[] getChildHandlersByClass(Class<?> var1);<T extends Handler> T getChildHandlerByClass(Class<T> var1);
}
实现类 说明
HandlerCollection 一个包含多个处理器的集合,按照顺序依次处理。这在响应请求的同时进行统计和日志记录特别有用。
HandlerList 一个包含多个处理器的集合,按照顺序处理,与HandlerCollection不同的是,当处理器出现异常或者响应被提交或者 request.isHandled() 方法返回true时,后续将不再被调用。一般用来匹配不同的主机,用来进行不同的处理。
HandlerWrapper 一个处理器的基类用来进行切面编程。例如,一个标准的web应用会由context,session,安全和servlet处理器构成。
ContextHandlerCollection 一个特殊的HandlerCollection,使用完整的URI前缀来选择匹配的ContextHandler对请求进行处理。

2.5 处理器的作用域 :

在Jetty中,很多标准的服务器会继承HandlerWrappers,用来进行链式处理,比如从请求从 ContextHandlerSessionHandler ,再到 SecurityHandler 最后到ServletHandler。然而,因为servlet规范的性质,外部处理器不能在没有调用内部处理器的时候得知内部处理器的信息,例如:ContextHandler调用应用监听请求的context时,它必须已经知道ServletHandler将要转发请求到哪个servlet,以确保servletPath方法返回正确的值。

ScopedHandler是HandlerWrapper 一个抽象实现类,用来提供链式调用时作用域的支持。例如:一个ServletHandler内嵌在一个ContextHandler中,方法嵌套调用的顺序为:

Server.handle(...)ContextHandler.doScope(...)ServletHandler.doScope(...)ContextHandler.doHandle(...)ServletHandler.doHandle(...)SomeServlet.service(...)

因此ContextHandler处理请求时,它内嵌的ServletHandler已经建立了。

2.6 嵌入 ResourceHandle

你可以使用 ResourceHandler 来处理当前工作路径下的静态资源。

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.handler.gzip.GzipHandler;import java.io.File;/*** <pre>* </pre>** @author saligia* @date 17-10-11*/
public class MyResource {public static void main(String [] args) throws Exception {Server server = new Server(8080);//创建一个ResourceHandler,它处理请求的方式是提供一个资源文件//这是一个Jetty内置的处理器,所以它非常适合与其他处理器构成一个处理链ResourceHandler resourceHandler = new ResourceHandler();//配置ResourceHandler,设置哪个文件应该被提供给请求方//这个例子里,配置的是当前路径下的文件,但是实际上可以配置长任何jvm能访问到的地方resourceHandler.setDirectoriesListed(true);resourceHandler.setWelcomeFiles(new String[] { "index.html" });resourceHandler.setResourceBase("src/main/web");// 将resource_handler添加到GzipHandler中,然后将GzipHandler提供给ServerGzipHandler gzip = new GzipHandler();server.setHandler(gzip);HandlerList handlers = new HandlerList();handlers.setHandlers(new Handler[] { resourceHandler, new DefaultHandler()});server.setHandler(handlers);server.start();server.join();}
}

在这个例子中,连接将处理http的请求,这个也是默认的ServerConnector连接类。

2.7 多个连接的例子

当配置多个连接(例如:HTTP和HTTPS),它们可能是共同分享HTTP设置的参数。为了显式的配置 ServerConnector 需要使用 ConnectionFactory ,并提供一个常用的HTTP配置。

下面这个 ManyConnectors例子,给一个Server配置了两个ServerConnector ,http连接有一个HTTPConnectionFactory 实例,https连接有一个SslConnectionFactory 实例在HttpConnectionFactory里面。两个HttpConnectionFactory 都是基于同一个HttpConfiguration实例,然而https使用包装过的配置信息,因此SecureRequestCustomizer 可以被添加进去。

import java.io.File;
import java.io.FileNotFoundException;import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.util.ssl.SslContextFactory;/*** 一个有多个连接的Jetty例子*/
public class ManyConnectors {public static void main(String[] args) throws Exception {//这个例子会展示如何配置SSL,我们需要一个秘钥库,会在jetty.home下面找String jettyDistKeystore = "../../jetty-distribution/target/distribution/demo-base/etc/keystore";String keystorePath = System.getProperty("example.keystore", jettyDistKeystore);File keystoreFile = new File(keystorePath);if (!keystoreFile.exists()) {throw new FileNotFoundException(keystoreFile.getAbsolutePath());}//创建一个不指定端口的Server,随后将直接配置连接和端口Server server = new Server();//HTTP配置//HttpConfiguration是一个配置http和https属性的集合,默认的配置是http的//带secured的ui配置https的,HttpConfiguration http_config = new HttpConfiguration();http_config.setSecureScheme("https");http_config.setSecurePort(8443);http_config.setOutputBufferSize(32768);//HTTP连接//第一个创建的连接是http连接,传入刚才创建的配置信息,也可以重新设置新的配置,如端口,超时等ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(http_config));http.setPort(8080);http.setIdleTimeout(30000);//使用SslContextFactory来创建http//SSL需要一个证书,所以我们配置一个工厂来获得需要的东西SslContextFactory sslContextFactory = new SslContextFactory();sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath());sslContextFactory.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");sslContextFactory.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");//HTTPS的配置类HttpConfiguration https_config = new HttpConfiguration(http_config);SecureRequestCustomizer src = new SecureRequestCustomizer();src.setStsMaxAge(2000);src.setStsIncludeSubDomains(true);https_config.addCustomizer(src);//HTTPS连接//创建第二个连接,ServerConnector https = new ServerConnector(server,new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()),new HttpConnectionFactory(https_config));https.setPort(8443);https.setIdleTimeout(500000);// 设置一个连接的集合server.setConnectors(new Connector[] { http, https });// 设置一个处理器server.setHandler(new HelloHandler());// 启动服务server.start();server.join();}
}

2.8 ServletHandle

Servlets 是处理逻辑和HTTP请求的标准方式。Servlets 类似于Jetty的处理器,request对象不可变且不能被修改。在Jetty中servlet将有ServletHandler进行负责调用。它使用标准的路径匹配一个请求到servlet,设置请求的路径和请求内容,将请求传递到servlet,或者通过过滤器产生一个响应。

import java.io.IOException;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;public class MinimalServlets {public static void main(String[] args) throws Exception {Server server = new Server(8080);//ServletHandler通过一个servlet创建了一个非常简单的context处理器//这个处理器需要在Server上注册ServletHandler handler = new ServletHandler();server.setHandler(handler);//传入能匹配到这个servlet的路径//提示:这是一个未经处理的servlet,没有通过web.xml或@WebServlet注解或其他方式配置handler.addServletWithMapping(HelloServlet.class, "/*");server.start();server.join();}@SuppressWarnings("serial")public static class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html");response.setStatus(HttpServletResponse.SC_OK);response.getWriter().println("<h1>Hello from HelloServlet</h1>");}}
}

2.9 嵌入 Context(ContextHandler)

  • ContextHandler是一种ScopedHandler,只用来响应配匹配指定URI前缀的请求,
  • 一个Classloader 当在一个请求作用域里的时候处理当前线程的请求
  • 一个ServletContext有小属性的集合
  • 通过ServletContext获得的初始化参数的集合
  • 通过ServletContext 获得的基础资源的集合
  • 一个虚拟主机名称的集合
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ResourceHandler;/*** <pre>*     一个简单的 jetty 服务* </pre>** @author saligia* @date 17-10-10*/
public class MyServer {public static void main(String [] args) throws Exception {Server server = new Server(8080);  // 创建一个 jetty 服务ContextHandler contextHandler = new ContextHandler();ResourceHandler resourceHandler = new ResourceHandler();//配置ResourceHandler,设置哪个文件应该被提供给请求方//这个例子里,配置的是当前路径下的文件,但是实际上可以配置长任何jvm能访问到的地方resourceHandler.setDirectoriesListed(true);resourceHandler.setWelcomeFiles(new String[] { "index.html" });resourceHandler.setResourceBase("src/main/web");contextHandler.setContextPath("/test");contextHandler.setHandler(resourceHandler);server.setHandler(contextHandler);server.start();server.join();}
}

2.10 嵌入 ServletContextHandler

ServletContextHandler是一种特殊的ContextHandler,它可以支持标准的sessions 和Servlets。下面例子的OneServletContext 实例化了一个 DefaultServlet为/tmp/ 和DumpServlet 提供静态资源服务,DumpServlet 创建session并且应答请求信息

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;public class OneServletContext {public static void main(String[] args) throws Exception {Server server = new Server(8080);ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);context.setContextPath("/");context.setResourceBase(System.getProperty("java.io.tmpdir"));server.setHandler(context);// 增加一个 dump servletcontext.addServlet(DumpServlet.class, "/dump/*");// 增加一个默认的servletcontext.addServlet(DefaultServlet.class, "/");server.start();server.join();}
}

当有很多有效的contexts 时,可以创建一个ContextHandlerCollection 集合存储这些处理器,下面的这个ManyContexts例子展示多个context的使用:

import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;public class ManyContexts
{public static void main( String[] args ) throws Exception{Server server = new Server(8080);ContextHandler context = new ContextHandler("/");context.setContextPath("/");context.setHandler(new HelloHandler("Root Hello"));ContextHandler contextFR = new ContextHandler("/fr");contextFR.setHandler(new HelloHandler("Bonjoir"));ContextHandler contextIT = new ContextHandler("/it");contextIT.setHandler(new HelloHandler("Bongiorno"));ContextHandler contextV = new ContextHandler("/");contextV.setVirtualHosts(new String[] { "127.0.0.2" });contextV.setHandler(new HelloHandler("Virtual Hello"));ContextHandlerCollection contexts = new ContextHandlerCollection();contexts.setHandlers(new Handler[] { context, contextFR, contextIT,contextV });server.setHandler(contexts);server.start();server.join();}
}

2.11 嵌入 web 应用(WebAppContext):

WebAppContext是ServletContextHandler 的扩展,使用标准的web应用组件和web.xml,通过web.xml和注解配置servlet,filter和其它特性。下面这个OneWebApp例子部署了一个简单的web应用。Web应用程序可以使用容器提供的资源,在这种情况下需要一个LoginService并配置:

import java.io.File;
import java.lang.management.ManagementFactory;import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
import org.eclipse.jetty.webapp.WebAppContext;public class OneWebApp {public static void main(String[] args) throws Exception {Server server = new Server(8080);// 设置 JMXMBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());server.addBean(mbContainer);//下面这个web应用是一个完整的web应用,在这个例子里设置/为根路径,web应用所有的配置都是有效的,WebAppContext webapp = new WebAppContext();webapp.setContextPath("/");File warFile = new File("../../jetty-distribution/target/distribution/test/webapps/test/");webapp.setWar(warFile.getAbsolutePath());webapp.addAliasCheck(new AllowSymLinkAliasChecker());//将web应用设置到server里server.setHandler(webapp);server.start();server.join();}
}

servlet 3 的新特性通过继承 ServletContainerInitializer 类来实现web.xml,如果用户有实现这个接口,可以通过这种配置方式启动

public class Main {public static void main(String[] args) throws Exception {Server server = new Server();// 链接管理ServerConnector serverConnector = new ServerConnector(server);serverConnector.setPort(8080);serverConnector.setReuseAddress(true);server.setConnectors(new Connector[]{serverConnector});WebAppContext context = new WebAppContext();context.setContextPath("/");context.setParentLoaderPriority(true);context.setResourceBase("lib");context.setConfigurations(new Configuration[] {new AnnotationConfiguration(),new WebInfConfiguration(), new EnvConfiguration() });context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*.jar");server.setHandler(context);server.start();server.dumpStdErr();server.join();}
}

Jetty篇教程 之Jetty 嵌入式服务器相关推荐

  1. Jetty使用教程(四:24-27)—Jetty开发指南

    二十四.处理器(Handler ) 24.1 编写一个常用的Handler Jetty的Handler组件用来处理接收到的请求. 很多使用者不需要编写Jetty的Handler ,而是通过使用Serv ...

  2. jetty 配置jndi_使用Jetty设置JNDI(嵌入式)

    jetty 配置jndi 我在开发工作区上运行嵌入式Jetty,从而节省了一些恶性的编译和部署周期. 我与Jetty的合作不多,易用性使我着迷于它. 我需要设置JNDI才能检索与数据库相关的活动的连接 ...

  3. Jetty篇一之初识Jetty

    前言: 最近公司项目中用到了Jetty来作为项目的web容器,借此机会来分享一下我的学习心得.在学习Jetty之前,一定要了解一些Jetty的基本概念以及优缺点,这样才方便做更深入的学习,现在让我来慢 ...

  4. Jetty使用教程(四:23)—Jetty开发指南

    二十三.Maven和Jetty 这一章节将说明如何通过Maven管理Jetty和使用Jetty的Maven插件. 23.1 使用Maven Apache Maven是一个款软件项目管理工具.基于项目对 ...

  5. Unity3D教程宝典之Web服务器篇:(第二讲)从服务器下载图片

    转载自风宇冲Unity3D教程学院                                     从Web服务器下载图片 上一讲风宇冲介绍了wamp服务器及安装.这回介绍如何从服务器下载内容 ...

  6. Jetty入门(1-1)Jetty入门教程

    一.Jetty是什么? 1.Jetty 是一个Java语言编写的,开源的Servlet容器和应用服务器. Jetty 极度轻量级.高便携性.功能强大.灵活和扩展性好,而且支持各种技术如SPDY.Web ...

  7. 使用O2OA二次开发搭建企业办公平台(二)平台部署篇:端口冲突和服务器端口配置

    本博客为O2OA系列教程.O2OA使用手册,教程目录和各章节天梯将在连载完后更新. 使用O2OA二次开发搭建企业办公平台(一)平台部署篇:平台下载和部署 使用O2OA二次开发搭建企业办公平台(二)平台 ...

  8. Jetty是什么?Jetty介绍以及配置

    转载自:http://jiajunde.javaeye.com/blog/373262 Jetty是什么 Jetty项目简介 Jetty是一个开源.基于标准.全功能实现的Java服务器.它在Apach ...

  9. html嵌入war_WAR文件与具有嵌入式服务器的Java应用程序

    html嵌入war 大多数服务器端Java应用程序(例如,面向Web或面向服务的)都打算在容器中运行. 打包这些应用程序以进行分发的传统方法是将它们捆绑为WAR文件. 这只不过是具有标准目录布局的ZI ...

最新文章

  1. 从性能角度选购Adroid智能手机,双核、大屏与游戏的取舍
  2. MySQL执行原理,逻辑分层、更改数据库处理引擎
  3. Chrome开发者工具关于网络请求的一个隐藏技能 1
  4. excel下划线转驼峰公式
  5. nssl1511-我的世界【堆,贪心】
  6. 云计算架构设计6大原则,你遵循了吗?| 赠书
  7. abp框架mysql连接配置,abp框架连接数据库
  8. mac安装python3.8_mac安装pwntools(python3.8)解决多数问题
  9. 上一页下一页html样式,软件 | hexo博客主题yilia上一页下一页显示的问题
  10. 移动网络安全_新突破!青海移动在2020年中国移动网络安全运维技能竞赛大赛中荣获三等奖!...
  11. java day11【final、权限、内部类、引用类型】
  12. python模块:时间处理模块
  13. [Luogu1216][USACO1.5]数字三角形 Number Triangles
  14. 让Latex支持中文
  15. Google搜索技巧终极收集
  16. obspy中文教程(六)
  17. 雨天美图大法:单图去雨的RESCAN新方式
  18. 2013 中国15大云平台
  19. 小程序如何从0裂变开始获客?
  20. 玩家交互体验—剑网3聊天系统

热门文章

  1. TensorFlow TFRecords简介
  2. TensorFlow Lite 开发手册(5)——TensorFlow Lite模型使用实例(分类模型)
  3. 最近项目用到Dubbo框架,临时抱佛脚分享一下共探讨。
  4. 云服务器除了阿里云外其他哪个比较好?
  5. 全国计算机建模三等奖,青春榜样 | 吴昊 : 守得云开见月明
  6. 程序与进程的区别 和 联 系
  7. python web论坛_十个基于Python的BBS论坛类开源web框架汇总(附源码地址)
  8. 十年磨一剑,霜刃未曾试(纪念最爱——加内特)
  9. IDEA跳至行首行末快捷键
  10. 消除switch/case语句,不破坏代码的封闭性,使程序结构更符合面向对象思想(二)