内置jetty
jetty有一个口号,不要把你的应用部署到jetty,而是把jetty部署到你的应用中。这说明使用jetty有两种选择,一种选择是将你的应用部署到jetty容器中,另一种选择是将jetty嵌入到你的应用层序中,后者意味着将一个http的模块嵌入到了你的程序中,而不是把你的程序放入一个http的server中。
这个文档就是帮助你一步一步将jetty嵌入到你的程序中。
1.概述
把jetty嵌入到你的程序中,一般都是下面的步骤:
- 创建一个server实例
- 增加或者配置connector
- 增加或者配置handler、context、servlet
- 启动server
- 等待连接
2.创建一个server
下面的代码创建了一个最简单的server。
import org.eclipse.jetty.server.Server;
/**
* Created by zdd on 2017/4/1.
*/
public class SimpleServer {
public static void main(String[] args) throws Exception{
Server server = new Server(8090);
server.start();
server.dumpStdErr();
server.join();
}
}
上面程序运行一个http server在8090端口。但是这个server没有任何用处,因为它没有任何handler,因此不管任何的请求都会返回404.
3.使用handler
为了对请求产生一个回应,jetty需要你在server上设置handler。一个handler可以:
- 检查或者修改HTTP请求。
- 生成response回应。
- 调用另一个handler(查看HandlerWrapper)
- 选择一个或者很多个handlers去调用(查看HandlerCollection)
3.1hello world Handler
下面的代码展示了一个最简单的helloworld handler:
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by zdd on 2017/4/1.
*/
public class HelloHandler extends AbstractHandler {
final String greeting;
final String body;
public HelloHandler(){
this("hello world");
}
public HelloHandler(String greeting){
this(greeting,null);
}
public HelloHandler(String greeting,String body){
this.greeting = greeting;
this.body = body;
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
response.setContentType("text/html;charset=utf-8");
response.setStatus(HttpServletResponse.SC_OK);
PrintWriter out = response.getWriter();
out.println("<h1>"+greeting+"</h1>");
if(body != null){
out.println(body);
}
baseRequest.setHandled(true);
}
}
传递给handle方法的参数有:
- target:请求的目标
- baseRequest:没有被包装的request对象
- request:不可变的request对象,可能被filter或者servlet包装过。
- response:请求的回应,也可能被filter或者servlet包装过。
handler会设置response的状态、response的内容类型、并且标记request被处理了,最后才通过out生成response的内容。
3.2运行helloworld Handler
为了允许handler去处理http请求,你必须把它绑定到server实例上。下面的代码显示了jetty server是如何和handler绑定的。
import org.eclipse.jetty.server.Server;
/**
* Created by zdd on 2017/4/1.
*/
public class SimpleServer {
public static void main(String[] args) throws Exception{
Server server = new Server(8090);
server.setHandler(new HelloHandler());
server.start();
server.join();
}
}
在jetty中,一般总会有一个或者多个handler区处理所有的请求。有些handler会选择其他指定的handler去做处理,例如(一个ContextHandlerCollection使用context path去选择ContextHandler);还有一些是使用程序的逻辑去产生response,例如(ServletHandler将请求转发给Servlet来处理),还有其他的一些是做一些无关的任务来生成response,例如(RequestLogHandler或者StatisticsHandler)。
后面的章节描述了你可以像切面一样合并多个handler。你可以看到一些有价值的handler在org.eclipse.jetty.server.handler包中。
4.Handler Collections and Wrappers
复杂的请求需要你合并多个handler来处理。jetty提供了几个HandlerContainer接口的实现:
- HandlerCollection:拥有一个handler的集合并且调用顺序调用每个handler。当你想合并统计和日志的handler这是很有用的。
- HandlerList:一个handler的集合,会依次调用这个集合里面的handler,直到如果有异常发生、response已经被提交、resquest.isHandled()被调用。你可以使用这个来合并一些handler,例如调用handler来处理直到被匹配到的情况下。
- HandlerWrapper:你可以使用这个来完成连接handlers类似于面向切面编程的风格。例如,一个标准的web程序被实现成一个context、session、security和servlet的串联。
- ContextHandlerClollection:一个特殊的HandlerCollection,使用最长uri匹配原则来选择handler。
5.Scoped Handlers
Server.handle(...)
ContextHandler.doScope(...)
ServletHandler.doScope(...)
ContextHandler.doHandle(...)
ServletHandler.doHandle(...)
SomeServlet.service(...)
6.Resource Handler
下面的代码给你展示了你可以使用ReourceHandler去处理静态的资源。
public class FileServer {
public static void main(String[] args) throws Exception{
// 创建一个最基本的jetty server并且绑定8090端口
// 如果把端口指定为0,那么程序会自动选择一个可用的端口
Server server = new Server(8090);
ResourceHandler resourceHandler = new ResourceHandler();
// 设置resourceHandler监听的目录
resourceHandler.setDirectoriesListed(true);
resourceHandler.setWelcomeFiles(new String[]{"idenx.html"});
resourceHandler.setResourceBase(".");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{resourceHandler, new DefaultHandler()});
server.setHandler(handlers);
server.start();
server.join();
}
}
注意我们使用了ResourceHandler和DefaultHandler,所以DefaultHandler对于没有匹配的请求会友好的返回404。
7.内置connectors
在上面的例子中,server实例都会绑定一个端口并且创建一个默认的connector来监听这个端口。但是,在内置jetty中,自定义一个或者多个connetor是很常见的。
7.1一个connector
public class OneConnector {
public static void main(String[] args) throws Exception{
Server server = new Server();
ServerConnector http = new ServerConnector(server);
http.setHost("localhost");
http.setPort(8090);
http.setIdleTimeout(30000);
server.addConnector(http);
server.setHandler(new HelloHandler());
server.start();
server.join();
}
}
在这个例子里connector处理http协议,因为这是ServerConnetor默认的配置。
7.2多connector
当配置多connector的时候,最好是多个connector享用相同的配置信息。为了实现这个你需要明确的指定serverConnector的配置,使用的是ConnectionFactory这个实例。
8内置servlets
servlet是让应用程序通过逻来处理请求的标准的方式。servlet和handler很相似。servlet在jetty中是被ServletHandler处理的。它使用标准的路径映射到一个servlet。
下面的代码创建了一个ServletHandler并且配置了一个简单的HelloServlet:
public class MinimalServlets {
public static void main(String[] args) throws Exception{
Server server = new Server(8090);
ServletHandler handler = new ServletHandler();
server.setHandler(handler);
// 需要注意的是,这是个原生的servlet,你可以通过web.xml或者@WebServlet来配置
handler.addServletWithMapping(HelloServlet.class,"/*");
server.start();
server.join();
}
}
class HelloServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().println("<h1>hello from HelloServlet</h1>");
}
}