文件服务器 ContextHandler Servlets ServletContextHandler Connectors JMX
添加依赖
1 2 3 4 5 6 <dependency > <groupId > org.eclipse.jetty</groupId > <artifactId > jetty-server</artifactId > <version > 9.4.0.M0</version > </dependency >
HandlerCollection
:维持一个handlers 集合, 然后按顺序依次调用每个handler(注意这个里的handler不管发生什么情况都会执行一遍, 这通常可以作为一个切面用于统计和记日志).
HandlerList
:同样维持一个handlers 集合,也是按顺序调用每个handler.但是当有异常抛出, 或者有response返回, 或者 request.isHandled()
被设为true.
HandlerWrapper
:继承自HandlerWrapper
的类可以以面向切面编程的方式将handler通过链式的形式组合在一起.例如一个标准的web应用程序就实现了一个这样的规则, 他将context,session,security,servlet的handler以链式的方式组合在一起.
文件服务器 通过ResourceHandler
指定了资源路径,并且允许列出目录和文件. 下面的例子中就是直接将ResourceHandler
映射到根目录/
下, 即通过http://localhost:8080/
就可以在浏览器上看到所有的文件列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import org.eclipse.jetty.server.Server;import org.eclipse.jetty.server.handler.ContextHandler;import org.eclipse.jetty.server.handler.HandlerList;import org.eclipse.jetty.server.handler.ResourceHandler;import org.eclipse.jetty.server.handler.gzip.GzipHandler;public class Main { public static void main (String[] args) throws Exception { Server server = new Server(8080 ); ResourceHandler fileResourceHandler = new ResourceHandler(); fileResourceHandler.setDirectoriesListed(true ); fileResourceHandler.setResourceBase("D:\\repository" ); GzipHandler gzip = new GzipHandler(); server.setHandler(gzip); ContextHandler fileContext = new ContextHandler("/files" ); fileContext.setHandler(fileResourceHandler); ResourceHandler indexResourceHandler = new ResourceHandler(); indexResourceHandler.setDirectoriesListed(true ); indexResourceHandler.setWelcomeFiles(new String[]{"index.html" }); indexResourceHandler.setResourceBase("." ); ContextHandler indexContextHandler = new ContextHandler("/" ); indexContextHandler.setHandler(indexResourceHandler); HandlerList handlerList = new HandlerList(); handlerList.addHandler(fileContext); handlerList.addHandler(indexContextHandler); server.setHandler(handlerList); server.start(); server.join(); } }
还可以使用ContextHandler
将ResourceHandler
映射到其他路径上.
ContextHandler ContextHandler
实现自ScopedHandler
. ContextHandler
实现的功能是将Http请求路径映射到某个具体处理业务逻辑的Handler上.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import org.eclipse.jetty.server.Handler;import org.eclipse.jetty.server.Request;import org.eclipse.jetty.server.Server;import org.eclipse.jetty.server.handler.AbstractHandler;import org.eclipse.jetty.server.handler.ContextHandler;import org.eclipse.jetty.server.handler.ContextHandlerCollection;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class ManyContexts { public static void main (String[] args) throws Exception { Server server = new Server(8080 ); ContextHandler rootContext = new ContextHandler("/" ); rootContext.setContextPath("/root" ); rootContext.setHandler(new HelloHandler("Root Hello" )); ContextHandler contextFR = new ContextHandler("/fr" ); contextFR.setHandler(new HelloHandler("Bonjoir" )); ContextHandler contextV = new ContextHandler("/" ); contextV.setVirtualHosts(new String[] { "127.0.0.2" }); contextV.setHandler(new HelloHandler("Virtual Hello" )); ContextHandler resourceBaseHandler = new ContextHandler("/resources" ); resourceBaseHandler.setResourceBase("/" ); resourceBaseHandler.setHandler(new HelloHandler("Resource Hello" )); ContextHandlerCollection contexts = new ContextHandlerCollection(); contexts.setHandlers(new Handler[] { rootContext, contextFR, contextV, resourceBaseHandler}); server.setHandler(contexts); server.start(); server.join(); } public static class HelloHandler extends AbstractHandler { private String path; public HelloHandler (String path) { this .path = path; } @Override public void handle (String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { ServletOutputStream out = response.getOutputStream(); out.print(path); out.flush(); response.setStatus(200 ); } } }
我们看一下测试结果
1 2 3 4 5 6 7 8 9 ζ curl http://192.168.10.220:8080/ Root Hello% ζ curl http://192.168.10.220:8080/fr ζ curl http://192.168.10.220:8080/it ζ curl 127.0.0.2:8080/ Virtual HelloRoot Hello%
Servlets Servlet是一种标准的处理HTTP请求逻辑的方式. Servlet和Jetty Handler非常像, 但是Servlet得request对象是不可变的. Jetty的ServletHandler采用将请求映射到一个标准路径上.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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 handler = new ServletHandler(); server.setHandler(handler); handler.addServletWithMapping(HelloServlet.class, "/*" ); server.start(); server.join(); } public static class HelloServlet extends HttpServlet { @Override protected 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>" ); } } }
ServletContextHandler 在上面的Servlets
中我们看到每个Servlet都对应一个完整的URI地址映射, 但是如果我们想在某个特定的URI下, 增加子映射怎么办呢?这就用到了ServletContextHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import org.eclipse.jetty.server.Server;import org.eclipse.jetty.servlet.ServletContextHandler;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;public class ServletContextHandlerTest { public static void main (String[] args) throws Exception { Server server = new Server(8080 ); ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS); servletContextHandler.setContextPath("/servlet" ); servletContextHandler.addServlet(HelloServlet.class, "/abc" ); server.setHandler(servletContextHandler); server.start(); server.join(); } public static class HelloServlet extends HttpServlet { @Override protected 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>" ); } } }
Connectors 当创建N个connectors应用时, 一般我们会将通用的配置首先提取出来, 使用一个配置类配置这些通用配置. 然后在其他具体Connectors配置时将这个配置传递到具体配置类中, 这样一来就形成了一个链式配置形式.
首先生成一个keystore文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 D:\ssl>keytool -genkey -alias wm -keyalg RSA -keysize 1024 -keypass 123456 -validity 365 -keystore D:\ssl\wm.keystore -storepass 123456 您的名字与姓氏是什么? [Unknown]: wm 您的组织单位名称是什么? [Unknown]: wm 您的组织名称是什么? [Unknown]: wm 您所在的城市或区域名称是什么? [Unknown]: bj 您所在的省/市/自治区名称是什么? [Unknown]: bj 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=wm, OU=wm, O=wm, L=bj, ST=bj, C=cn是否正确? [否]: y D:\ssl>
然后看一下服务器代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.FileNotFoundException;import java.io.IOException;public class ManyConnectors { public static void main (String[] args) throws Exception { File keystoreFile = new File("D:\\ssl\\wm.keystore" ); if (!keystoreFile.exists()) { throw new FileNotFoundException(keystoreFile.getAbsolutePath()); } Server server = new Server(); HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.setSecureScheme("https" ); httpConfig.setSecurePort(8443 ); httpConfig.setOutputBufferSize(32768 ); ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); http.setPort(8080 ); http.setIdleTimeout(30000 ); SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath(keystoreFile.getAbsolutePath()); sslContextFactory.setKeyStorePassword("123456" ); sslContextFactory.setKeyManagerPassword("123456" ); HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig); SecureRequestCustomizer src = new SecureRequestCustomizer(); src.setStsMaxAge(2000 ); src.setStsIncludeSubDomains(true ); httpsConfig.addCustomizer(src); ServerConnector https = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(httpsConfig)); https.setPort(8443 ); https.setIdleTimeout(500000 ); server.setConnectors(new Connector[] { http, https }); ServletHandler handler = new ServletHandler(); handler.addServletWithMapping(HelloServlet.class, "/*" ); server.setHandler(handler); server.start(); server.join(); } public static class HelloServlet extends HttpServlet { @Override protected 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>" ); } } }
我们使用JMeter模拟客户端进行访问
JMX 服务器开启JMX
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import java.lang.management.ManagementFactory;import javax.management.remote.JMXServiceURL;import org.eclipse.jetty.jmx.ConnectorServer;import org.eclipse.jetty.jmx.MBeanContainer;import org.eclipse.jetty.server.Server;public class ServerWithJMX { public static void main (String[] args) throws Exception { MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); Server server = new Server(8080 ); server.addBean(mbContainer); ConnectorServer jmx = new ConnectorServer( new JMXServiceURL("rmi" , null , 1999 , "/jndi/rmi://localhost:1999/jmxrmi" ), "org.eclipse.jetty.jmx:name=rmiconnectorserver" ); server.addBean(jmx); server.start(); server.dumpStdErr(); server.join(); } }