Jetty
Jetty是一个web容器,它可以作为一个传统的web容器,也可以作为一个动态的内容服务器,并且jetty可以非常容易的嵌入到java应用程序当中
Jetty特性
易用性
易用性是jetty设计的基本原则,主要体现在以下几个方面:
通过XML或者API来对jetty进行配置
默认配置可以满足大部分的需求
将jetty嵌入到应用程序当中只需要非常少的代码
可扩展性
在使用了Ajax的Web2.0的应用程序中,每个连接需要保持更长的时间,这样线程和内存的消耗量就会极具增加,这就使得我们担心整个程序会因为单个组件陷入瓶颈而影响整个程序的性能,但是Jetty可以:
即使在有大量服务请求的情况下,系统的性能也能保持在一个可以接受的状态
利用Continuation机制来处理大量的用户请求以及时间比较长的连接
另外Jetty设计了非常良好的接口,因此在Jetty的某种实现无法满足用户的需要时,用户可以非常方便的对jetty的某种实现进行修改,使得jetty适用于特殊的应用程序的需求
易嵌入性
jetty设计之初就是作为一个优秀的组件来设计的,这也就意味着jetty可以非常容易的嵌入到应用程序当中,而不需要为了使用jetty做修改。从某种程度上,也可以把jetty理解为一个嵌入式的web服务器。
部署应用程序
Jetty部署应用有多种使用方式:服务器部署应用,在项目中启动Jetty,在Spring项目中替换tomcat。
服务器部署应用
要将自己的程序部署到jetty上面比较简单,首先先将开发好的程序打成war包放到jetty的webapps目录下面。然后用 java -jar start.jar 启动服务器,在启动服务器后,我们就能够访问应用程序了。jetty默认的端口是8080,war的名字也就是我们的应用程序的根上下文。
hello.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>webapp</title>
</head>
<body>
<p>hello netty</p>
</body>
</html>程序结构:

将程序打包为war包,将war存放在jetty项目的webapps目录下,然后再部署jetty项目,uri为war包名。(忽略我把jetty写成netty了)

项目中启动Jetty
Jetty可以在项目中启动,作为Web项目的服务器。下面是一个简单的例子。
在pom中引入依赖:
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.50.v20221201</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.50.v20221201</version>
</dependency>JettyServer:
public class JettyServer {
public static void startJettyServer() throws Exception {
//项目名,用做一级地址
String homeURI = "jetty";
//用Server启动Jetty
Server server = new Server(8081);
//创建一个ContextHandler 用它来配置要执行的servlet 也可以使用WebAppContext
ServletContextHandler servletContextHandler = new ServletContextHandler();
//设置项目uri
servletContextHandler.setContextPath("/" + homeURI);
//向handler中添加servlet
servletContextHandler.addServlet(HelloServlet.class,"/hello");
//设置服务器Handlers
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[]{servletContextHandler,new DefaultHandler()});
server.setHandler(handlers);
//开启服务器
server.start();
System.out.println("server start");
server.join();
}
}HelloServlet:
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setIntHeader("Refresh", 5);
resp.setContentType("text/html;charset=UTF-8");
Calendar calendar = Calendar.getInstance();
Date time = calendar.getTime();
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nowTime = df.format(time);
PrintWriter out = resp.getWriter();
String title = "Hello,Jetty";
String docType = "<!DOCTYPE html>\n";
out.print(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n"+
"<body>\n" +
"<h1>" + title + "</h1>\n" +
"<p>" + nowTime + "</p>\n"+
"</body></html>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}Main:
public class Main {
public static void main(String[] args) {
try {
JettyServer.startJettyServer();
} catch (Exception e) {
e.printStackTrace();
}
}
}结果:

在spring中使用Jetty替换Tomcat
在spring中使用Jetty替换Tomcat是比较简单的,只需要在pom中剔除Spring自带的Tomcat依赖,随后添加Jetty依赖,就可以达到替换Tomcat的目的,这种替换对开发是无感的,因为只是替换了Spring的servlet容器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--剔除tomcat-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
Jetty框架介绍
在Jetty中,万物皆为Handler。
在Jetty中,将监听器和责任链都整合到了Handler中。
在JettyServer中,主要就是两部分:Handler和Connector

Jetty的三种启动方式,最终都是通过Server启动。

JettyClassLoaderUML:

JettyConnectorUML

JettyServerUML:

JettyLifeCycleUML:

JettyHandlerUML:

Jetty启动流程

Jetty请求流程

补充
handle方法
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
target - 请求的目标,它是URI或命名调度程序的名称。
baseRequest - Jetty可变请求对象,没有被包装的request对象。
request - 不可变请求对象,可能已被filter或servlet包装。
response- 响应,可能已被过滤器或servlet包装。
关于Handler
在Jetty中一般有一个或者多个handler来处理所有的请求。有些handler会选择其他指定的handler去做处理(例如ContextHandlerCollection会通过context path来选择ContextHandler); 还有一些handler通过应用程序逻辑生成响应(例如,ServletHandler将请求传递给应用Servlet),其他的handler则执行与生成响应无关的任务(例如,RequestLogHandler或StatisticsHandler)。
Handler Collection and Wrappers
复杂请求通常由多个Handler构建,可以通过各种方式进行组合,
HandlerCollection:
保存其他 handler 集合并按顺序调用每个handler。这对于将统计信息和日志记录 handler 与生成响应的 handler 相结合非常有用。
HandlerList:
一个Handler 集合,它依次调用每个 handler,直到抛出异常,响应被提交或request.isHandled() 返回true。您可以使用它来组合handler有选择的处理请看清,例如调用多个Context上下文直到与虚拟主机匹配。
HandlerWrapper:
一个Handler基类,可用于以面向切面编程的方式将处理程序连接在一起。例如,标准Web应用程序由上下文,会话,安全性和servlet处理程序链实现。
ContextHandlerCollection:
一个专门的HandlerCollection,它使用请求URI的最长前缀(contextPath)来选择一个包含的ContextHandler来处理请求。
ScopedHandlers
Jetty中的大部分标准Servlet容器都是使用HandlerWrappers实现的,它们将handler 以链式组合在一起:ContextHandler --> SessionHandler --> SecurityHandler --> ServletHandler。 但是,由于servlet规范,这种 handler 链不能是纯粹的嵌套,因为外部 handler 有时需要内部 handler 的处理信息。 例如,当ContextHandler调用某些应用程序listener以通知它们进入上下文的请求时,它必须已经知道ServletHandler将向哪个servlet分派请求,以便servletPath方法返回正确的值。
HandlerWrapper是ScopedHandler抽象类,它支链式链scopes。 例如,如果ServletHandler嵌套在ContextHandler中,则方法执行的顺序和嵌套是:
Server.handle(...)
ContextHandler.doScope(...)
ServletHandler.doScope(...)
ContextHandler.doHandle(...)
ServletHandler.doHandle(...)
SomeServlet.service(...)