首先来建一个web应用:
mvn archetype:create -DgroupId=com.wszt -DartifactId=webtest -DarchetypeArtifactId=maven-archetype-webapp -DinteractivMode=false
然后增加Jetty的依赖:
<!-- Jetty -->
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.24</version>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jsp-2.1</artifactId>
<version>7.0.0pre2</version>
</dependency>
再写一个main函数就可以启动应用了:
public class Jetty {
public static void main(String[] args) throws Exception {
Server server = new Server();
// 设置Connector
SocketConnector connector = new SocketConnector();
connector.setPort(80);
server.addConnector(connector);
// 设置WebAppContext
WebAppContext context = new WebAppContext();
context.setDescriptor("webapp/WEB-INF/web.xml");
context.setResourceBase("src/main/webapp");
context.setContextPath("/");
server.setHandler(context);
// 启动
server.start();
}
}
下面来看Jetty内部是如何运行的。
在jetty启动之后,会在Connector中根据你的配置信息监听端口,当有请求达到的时候将Socket封装成Connection然后进行处理,流程如下:
接着来看,在socket中读取到的是字节数组,在拿到数据之后需要通过HttpParser对其进行解析。在其中定义了21种状态,每读取一个byte后根据当前的状态进行处理以及状态的修改。HttpParser暴露给调用者一个回调接口使得调用方对不同阶段解析出来的内容进行处理:
public static abstract class EventHandler {
public abstract void content(Buffer ref) throws IOException;
public void headerComplete() throws IOException { }
public void messageComplete(long contentLength) throws IOException { }
public void parsedHeader(Buffer name, Buffer value) throws IOException { }
public abstract void startRequest(Buffer method, Buffer url, Buffer version) throws IOException;
public abstract void startResponse(Buffer version, int status, Buffer reason) throws IOException;
}
另外一个工具是HttpGenerator,用来处理请求的生成和响应的发送。
在HttpConnection完成准备之后,将request交给server进行处理,然后将结果(response)返回,主要的逻辑在handleRequest中,简化代码:
protected void handleRequest() throws IOException {
if (_server.isRunning()) {
boolean retrying = false;
boolean error = false;
String info=null;
try {
// 设置request的pathInfo
info = URIUtil.canonicalPath(_uri.getDecodedPath());
if (info == null)
throw new HttpException(400);
_request.setPathInfo(info);
// 设置socket信息以及forward头处理
if (_out != null)
_out.reopen();
_connector.customize(_endp,_request);
// 扔给server处理
_server.handle(this);
} finally {
if (!retrying) {
// 取消Continuation上的所有等待状态
if (_request.getContinuation() != null) {
_request.getContinuation().reset();
}
if (_endp.isOpen()) {
if (_generator.isPersistent())
_connector.persist(_endp);
if (error)
_endp.close();
else {
if (!_response.isCommitted() && !_request.isHandled())
_response.sendError(HttpServletResponse.SC_NOT_FOUND);
_response.complete();// 请求完成
}
} else {
_response.complete();// 请求完成
}
}
}
}
}
在Jetty中通过Continuation可以将请求挂起、唤醒(请求的异步化可以看这里),在程序中要使用的时候可以通过ContinuationSupport获取,提供的操作主要有:
- suspend:挂起
- resume:恢复
核心的状态就是DISPATCHED、ASYNCWAIT、COMPLETED,其他状态主要是处理重新派发以及多线程之间的状态协调。来看request、response交给server之后的处理过程。
---------- ---------- ---------- ---------- ---------- 分割线 ---------- ---------- ---------- ---------- ----------