今天学习了一下Jetty的代码,版本为V8.1.17.v20150415
做个笔记,以防忘记
比较专业的jetty架构解析,可以参考如下链接
http://my.oschina.net/tryUcatchUfinallyU/blog?disp=1&catalog=300813&sort=time&p=2
http://www.ibm.com/developerworks/cn/web/wa-lo-jetty/
http://ipjmc.iteye.com/blog/1839999
http://www.blogjava.net/DLevin/archive/2014/05/07/413158.html
最好看完这11+1+1+1篇文章之后再看我写的以下内容,否则容易急功近利……
——————————————————————————————————————————————————————————————
——————————————————————————伟大的分割线——————————————————————————————
——————————————————————————————————————————————————————————————
jetty的架构为基于LifyCycle的架构,每个组件都实现了该接口,具有LifyCyle的生命周期
public interface LifeCycle{
public void start() throws Exception;
public void stop() throws Exception;
public boolean isRunning();
public boolean isStarted();
public boolean isStarting();
public boolean isStopping();
public boolean isStopped();
public boolean isFailed();
public void addLifeCycleListener(LifeCycle.Listener listener);
public void removeLifeCycleListener(LifeCycle.Listener listener);
public interface Listener extends EventListener
{
public void lifeCycleStarting(LifeCycle event);
public void lifeCycleStarted(LifeCycle event);
public void lifeCycleFailure(LifeCycle event,Throwable cause);
public void lifeCycleStopping(LifeCycle event);
public void lifeCycleStopped(LifeCycle event);
}
}
通过实现该接口,一个Class类就具有了生命周期,可以作为Jetty的组件来管理
——————————————————————————————————————————————————————————————
——————————————————————————伟大的分割线——————————————————————————————
——————————————————————————————————————————————————————————————
我们看一段简单的代码,这段代码实现了一个简单的web服务器
——————-pom.xml
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>8.1.17.v20150415</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>8.1.17.v20150415</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>8.1.17.v20150415</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jsp</artifactId>
<version>8.1.17.v20150415</version>
</dependency>
</dependencies>
——————————main方法
public static void main(String[] args) throws Exception {
Server server = new Server();
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMinThreads(10);
threadPool.setMaxThreads(100);
threadPool.setDetailedDump(false);
server.setThreadPool(threadPool);
SelectChannelConnector selectChannelConnector = new SelectChannelConnector();
selectChannelConnector.setHost(“0.0.0.0”);
selectChannelConnector.setPort(8080);
selectChannelConnector.setMaxIdleTime(3000000);
selectChannelConnector.setAcceptors(2);
selectChannelConnector.setStatsOn(false);
selectChannelConnector.setConfidentialPort(8443);
selectChannelConnector.setLowResourcesConnections(20000);
selectChannelConnector.setLowResourceMaxIdleTime(5000);
server.addConnector(selectChannelConnector);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath(“/“);
webAppContext.setWar(“E:/workspace/workspace-jetty/webapp/target/webapp.war”);
server.setHandler(webAppContext);
server.start();
server.join();
}
以上代码即为:把webapp.war作为一个服务发布出去。
——————————————————————————————————————————————————————————————
———————————————————————-Jetty服务器的组成结构————————————————————————————-
——————————————————————————————————————————————————————————————
首先我们来分析jetty的组成结构
如上一个main方法示例所示:一个jetty服务器由以下四部分组成:
Connector ———– Server ———– ThreadPool ———- Handler
从Jetty发布包中的etc/jetty.xml中你可以清楚的看到对应配置
如果想启动一个jetty服务器这四个组件必不可少
如果要想明确一下这四种组件的具体作用,可以大致定义如下:
1、Connector:常用的是SelectChannelConnector,
重要变量如下:
private final SelectorManager _manager = new ConnectorSelectorManager(); –连接选择管理器
重要方法如下:
open 打开一个新的SocketChannel通道
accept 尝试accept一个连接,如果发生连接,则将连接注册到SelectorManager中
newConnection 新建一个AsyncHttpConnection
newEndPoint 新建一个SelectChannelEndPoint
doStart 组件启动方法
2、Server:Jetty启动类
重要变量如下:
private final Container _container=new Container(); 组件容器
private ThreadPool _threadPool; 线程池
private Connector[] _connectors; 连接
重要方法如下:
doStart 组件启动方法
doStop 组件停止方法
start 继承自AbstractLifeCycle的启动方法
stop 继承自AbstractLifeCycle的停止方法
3、ThreadPool:Jetty线程池,常用实现类为QueuedThreadPool
重要变量如下:
private final ConcurrentLinkedQueue<Thread> _threads=new ConcurrentLinkedQueue<Thread>(); 可用线程
private BlockingQueue<Runnable> _jobs; 需要执行的任务
private Runnable _runnable = new Runnable()…… 默认启动任务:从_jobs中poll出一个任务并执行
重要方法如下
doStart 组件启动方法
doStop 组件停止方法
dispatch 将job任务增加到执行队列_jobs等待执行
startThread 在调用doStart时触发,启动_minThreads指定个数的“默认线程”_runnable默认任务
4、Handler:即处理器,Jetty使用了Handler处理器的架构
参见http://my.oschina.net/tryUcatchUfinallyU/blog/110553
从设计模板角度来看 Handler 的设计实际上就是一个责任链模式,接口类 HandlerCollection
可以帮助开发者构建一个链,而另一个接口类 ScopeHandler
可以帮助你控制这个链的访问顺序。另外一个用到的设计模板就是观察者模式,用这个设计模式控制了整个 Jetty 的生命周期,只要继承了
LifeCycle 接口,你的对象就可以交给 Jetty 来统一管理了。所以扩展 Jetty
非常简单,也很容易让人理解,整体架构上的简单也带来了无比的好处,Jetty 可以很容易被扩展和裁剪。
Handler的接口如下:
public interface Handler extends LifeCycle, Destroyable{
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;
public void setServer(Server server);
public Server getServer();
public void destroy();
}
HandlerContainer接口如下:
public interface HandlerContainer extends LifeCycle{
public Handler[] getHandlers();
public Handler[] getChildHandlers();
public Handler[] getChildHandlersByClass(Class<?> byclass);
public <T extends Handler> T getChildHandlerByClass(Class<T> byclass);
}
由代码可知:Handler的作用就是,对Request和Response对象进行处理,使之完成相应的功能。
示例中的Handler是WebAppContext,此外,Handler还可以是HandlerList和HandlerCollection,其区别在于HandlerList在责任链模式下,如果一个请求被标记为已处理过或者已经报异常,则不会继续处理;而HandlerCollection无论什么情况,会执行所有的Handler。
对WebAppContext的分析需要较大篇幅,本文不予分析。
——————————————————————————————————————————————————————————————
———————————————————————-Jetty服务器的启动顺序————————————————————————————-
——————————————————————————————————————————————————————————————
接下来我们来分析Jetty的启动顺序,网上的流程图很多,凑巧我的编辑器不能画图,所以我将启动顺序用写的方式写出来。
1、new Server()
1.1 初始化server对象
1.2 初始化Container容器
2、new QueuedThreadPool()
2.1 初始化_threads线程队列
3、server.setThreadPool(threadPool); 对服务器设置线程池
3.1 调用server的祖宗类AggregateLifeCycle.addBean方法,将bean注册入_beans
3.2 _container.addBean(threadPool) ——————–JettyV8.17版本似乎有BUG?此处代码会判断_listeners为0时不能加入对象,类似“空腹吃饭有害健康”的笑话。
4、new SelectChannelConnector() 新建一个ChannelConnector
4.1 初始化 private final SelectorManager _manager = new ConnectorSelectorManager();
4.2 调用addBean方法将_manager注册到SelectChannelConnector的祖宗类AggregateLifeCycle._beans中
4.3 设置 int _acceptors 根据(Runtime.getRuntime().availableProcessors+3)/4设置_acceptor的数量
5、server.addConnector(selectChannelConnector); 对服务器增加Connector
5.1 更新server._connectors 数组对象为新的connector数组
6、new WebAppContext() 新建Handler 比较复杂,不在此说明
7、server.setHandler(webAppContext);
7.1 _handler=handler赋值为hander
7.2 handler.setServer(getServer()); 建立server和handler的连接关系
8、server.start();启动Jetty服务器
8.1 server调用继承自AbstractLifeCycle的start方法
8.1.1 server调用继承自AbstractLifeCycle的setStarting()方法
8.1.2 server调用自身实现的抽象方法dostart
8.1.2.1 server.dostart方法中ShutdownMonitor.getInstance().start()启动停机监控
8.1.2.2 server.dostart方法中HttpGenerator设置服务器版本号8.1.17.v20150415
8.1.2.3 server.dostart方法中super.doStart();
8.1.2.3.1 server的父类HandlerWrapper.doStart(),调用父类doStart
8.1.2.3.1.1 如果server的_handler不为空,则执行_handler.start(); ——————————–
8.1.2.3.1.2 调用server的父类HandlerWrapper的父类AbstractHandler的父类AggregateLifeCycle的doStart方法
8.1.2.3.1.2.1 循环调用_beans.start()方法-》触发所有通过server.addBean注册到_beans中的组件的继承自LifeCycle的start方法
8.1.2.3.1.2.2 设置server对象的已启动标志_started为true
8.1.2.3.1.3 调用server的父类HandlerWrapper的父类AbstractHandler的父类AggregateLifeCycle的父类AbstractLifeCycle的dostart方法
8.1.2.4 server.dostart方法中:由于server.addConnector时,没有addBean,所以在8.1.2.3.1.2.1步骤没有调用connector的start方法
因此,server.dostart中,循环调用_connectors.start
8.1.3 server调用继承自AbstractLifeCycle的setStarted()方法
8.2 server调用继承自AbstractLifeCycle的start结束
9、接步骤8.1.2.3.1.1启动Handler继承自AbstractLifeCycle的start方法
10、接步骤8.1.2.3.1.2启动AggregateLifeCycle._beans中注册的LifyCycle
10.1 启动步骤3.1通过server.addBean注册到AggregateLifeCycle._beans中的LifeCycle->QueuedThreadPool.start
10.1.1 调用_beans.start,即QueuedThreadPool.start
10.1.2 QueuedThreadPool调用继承自父类AbstractLifeCycle的start方法
10.1.2.1 QueuedThreadPool调用继承自父类AbstractLifeCycle的setStarting方法
10.1.2.2 QueuedThreadPool调用自身实现的doStart方法
10.1.2.2.1 QueuedThreadPool调用继承自父类AbstractLifeCycle的doStart方法
10.1.2.2.2 QueuedThreadPool如果_jobs,任务队列为空,则对任务队列赋初始值ArrayBlockingQueue或者BlockingArrayQueue
10.1.2.2.3 QueuedThreadPool调用循环while(isRunning() && threads<_minThreads),新建_minThreads
10.1.2.2.3.1 QueuedThreadPool循环初始化线程时,调用startThread方法,新建线程
10.1.2.2.3.1.1 QueuedThreadPool.startThread调用newThread(_runnable)方法,创建一个实现了_runable接口的线程
备注:_runable接口功能为为从_jobs中取出一个任务,并且调用该任务的_job.run方法
10.1.2.2.3.1.2 启动新创建的_runable线程
10.1.2.2.4 QueuedThreadPool结束调用doStart方法
10.1.2.3 QueuedThreadPool调用继承自父类AbstractLifeCycle的setStarted方法
10.1.3 QueuedThreadPool结束调用继承自父类AbstractLifeCycle的start方法
11、接步骤8.1.2.4,server.doStart方法中,启动Connector组件,调用try{_connectors[i].start();}
(由于_connector没有注册到AggregateLifeCycle._beans中,也有可能是故意为之,使connector最后执行)
11.1 SelectChannelConnector调用继承自父类AbstractLifeCycle的start方法
11.1.1 SelectChannelConnector调用继承自父类AbstractLifeCycle的setStarting方法
11.1.2 SelectChannelConnector调用自身实现的doStart方法
11.1.2.1 SelectChannelConnector调用父类AbstractConnector的doStart方法
11.1.2.2 SelectChannelConnector调用自身实现的open方法
11.1.2.2.1 SelectChannelConnector初始化ServerSocketChannel _acceptChannel;
11.1.2.2.2 SelectChannelConnector将ServerSocketChannel _acceptChannel绑定到指定端口new InetSocketAddress(getPort())
11.1.2.2.3 SelectChannelConnector调用AggregateLifeCycle.addBean方法,将_acceptChannel注册入AggregateLifeCycle._beans
11.1.2.3 SelectChannelConnector结束调用自身实现的open方法
11.1.2.4 SelectChannelConnector调用父类AbstractConnector的父类AggregateLifeCycle的doStart方法
11.1.2.5 SelectChannelConnector的祖宗类AggregateLifeCycle检查_beans是否已经全部启动,如果没有启动,则调用start方法
11.1.2.5.1 在步骤4.2中,ConnectorSelectorManager被注册到了SelectChannelConnector的祖宗类AggregateLifeCycle._beans中,此处SelectChannelConnector的隐含对象ConnectorSelectorManager的start方法被调用
11.1.2.5.2 ConnectorSelectorManager调用继承自祖宗类AbstractLifeCycle的.start方法
11.1.2.5.3 ConnectorSelectorManager调用继承自祖宗类AbstractLifeCycle的.setStarting方法
11.1.2.5.4 ConnectorSelectorManager调用继承自父类SelectorManager实现的.doStart()方法
11.1.2.5.4.1 ConnectorSelectorManager的父类SelectorManager初始化_selectSet[]数组为新的SelectSet数组
11.1.2.5.4.2 ConnectorSelectorManager的父类SelectorManager调用父类AbstractLifeCycle.doStart()方法,空方法
11.1.2.5.4.3 SelectorManager.doStart中对SelectSet进行循环
11.1.2.5.4.3.1 创建新的Runable接口对象”循环调用SelectSet.doSelect”
11.1.2.5.4.3.2 将Runable接口对象通过调用ConnectorSelectorManager.dispatch方法,委托给QueuedThreadPool执行
11.1.2.5.5 ConnectorSelectorManager结束调用继承自父类SelectorManager实现的.doStart()方法
11.1.2.5.6 ConnectorSelectorManager调用继承自祖宗类AbstractLifeCycle的.setStarted方法
11.1.2.6 SelectChannelConnector的祖宗类AggregateLifeCycle设置_started启动标志为已启动
11.1.2.7 SelectChannelConnector的祖宗类AggregateLifeCycle调用父类AbstractLifeCycle.doStart()空方法
11.1.2.8 SelectChannelConnector结束调用父类AbstractConnector的父类AggregateLifeCycle的doStart方法
11.1.2.9 SelectChannelConnector结束调用父类AbstractConnector的doStart方法
11.1.2.10 SelectChannelConnector根据_acceptorThreads配置,创建相应数量的Acceptor委托给_threadPool执行
11.1.3 SelectChannelConnector结束调用自身实现的doStart方法
11.2 SelectChannelConnector调用继承自父类AbstractLifeCycle的setStarted方法
11.3 SelectChannelConnector的start结束。
12、接步骤11.1.2.10,SelectChannelConnector根据_acceptorThreads配置,创建相应数量的Acceptor委托给_threadPool执行
12.1 AbstractConnector的内部类Acceptor开始运行
12.2 Acceptor调用accept方法(由于是SelectorChannelConnector创建了父类AbstractConnector的内部类Acceptor对象,则Acceptor对象调用的AbstractConnector的抽象方法accept,最终调用的是SelectorChannelConnector的accept方法)
12.3 Acceptor调用SelectorChannelConnector的accept方法
12.4 SelectorChannelConnector.accept方法中开始accept阻塞SocketChannel channel = server.accept();
12.5 客户端发起连接
12.6 阻塞释放
12.7 SelectorChannelConnector.accept方法中,调用_manager.register(channel);,即SelectorManager.register(SocketChannel channel)
12.8 用取余算法随机取一个SelectorManager._selectSet[i]的SelecSet
12.9 将变更事件放入SelectSet中,调用wakup函数唤醒在SelectSet上睡眠的线程
13、接步骤11.1.2.5.4.3.2 将Runable接口对象”循环调用SelectSet.doSelect”通过调用ConnectorSelectorManager.dispatch方法,委托给QueuedThreadPool执行
13.1 SelectSet调用doSelect方法
13.2 从SelectSet内部对象ConcurrentLinkedQueue<Object> _changes变更事件队列中poll出一个事件
13.2.1 如果poll出的事件是EndPoint,进行相应处理
13.2.2 如果poll出的事件是ChannelAndAttachment,进行相应处理
13.2.3 如果poll出的事件是ChangeTask,则直接运行
13.2.4 如果poll出的事件是Runnable,则委托给线程池运行
13.2.5 如果poll出的事件是SocketChannel
13.2.5.1 在当前SelectSet的专用Selector上注册一个channel的read事件
13.2.5.2 调用createEndPoint方法创建一个SelectChannelEndPoint
13.2.5.2.1 调用newEndPoint方法,创建一个SelectChannelEndPoint
13.2.5.2.2 调用ConnectorSelectorManager.newEndPoint方法,return SelectChannelConnector.this.newEndPoint(channel,selectSet,sKey);
13.2.5.2.3 SelectChannelEndPoint endp= new SelectChannelEndPoint(channel,selectSet,key, SelectChannelConnector.this._maxIdleTime);
13.2.5.2.4 endp设置Connection为selectSet.getManager().newConnection(channel,endp, key.attachment())
13.2.5.2.4.1 调用ConnectorSelectorManager.newConnection方法,创造一个new AsyncHttpConnection(SelectChannelConnector.this,endpoint,getServer());
内部已经生成一系列解析HTTP的工具,如:
HttpBuffersImpl _buffers = new HttpBuffersImpl();
protected final Parser _parser;
protected final Request _request;
protected final HttpFields _requestFields;
protected final Generator _generator;
protected final HttpFields _responseFields;
protected final Response _response; 等
13.2.5.3 调用key.attach(endpoint);将SelectChannelEndPoint附加到channel读事件的key上
13.2.5.4 调用SelectChannelEndPoint.schedule()
13.2.5.4.1 正常情况下,调用SelectChannelEndPoint.dispatch
13.2.5.4.2 调用_manager.dispatch(_handler);即ConnectorSelectorManager.dispatcher方法,将_handler交给线程池执行
_handler接口如下
private final Runnable _handler = new Runnable()
{
public void run() { handle(); }
};
13.2.5.4.3 即:线程池会运行_handler接口,调用SelectChannelEndPoint.handle方法
13.2.5.4.3.1 调用AsyncConnection next = (AsyncConnection)_connection.handle(); 此处的AsyncConnection是在步骤13.2.5.2.4.1中生成
13.2.5.4.3.1.1 调用AsyncHttpConnection.handle()方法
13.2.5.4.3.1.2 调用AsyncHttpConnection的父类AbstractHttpConnection的类变量_parser的parseAvailable()方法
13.2.5.4.3.1.2.1 调用_parser的parseNext()方法
13.2.5.4.3.1.2.2 生成_buffer=getHeaderBuffer();–>从AsyncHttpConnection中获取new 时初始化的buffer
13.2.5.4.3.1.2.3 调用_parser的fill()方法给_buffer填充数据
13.2.5.4.3.1.2.3.1 调用_endp.fill(_buffer),即SelectChannelEndPoint.fill(_buffer)
13.2.5.4.3.1.2.3.2 调用SelectChannelEndPoint的父类ChannelEndPoint.fill(_buffer)方法
13.2.5.4.3.1.2.3.3 调用SelectChannelEndPoint的父类ChannelEndPoint的_channel.read(bbuf)方法填充数据,即:SocketChannelImpl.fill(bbuf)
13.2.5.4.3.1.2.3.4 结束调用_endp.fill(_buffer),即SelectChannelEndPoint.fill(_buffer)
13.2.5.4.3.1.2.4 结束调用_parser的fill()方法给_buffer填充数据
13.2.5.4.3.1.2.5 _parser开始解析http报文(起始代码HttpParse.java 343行while (_state<STATE_END && length–>0))
此处Http报文解析写的很经典,通过定义一定的状态位,控制解析报文的状态,从-14状态直至最终结束,推荐学习之,虽然这种写法很奇葩……
让我想起了以前我有幸参观的伟大的、独一无二的、软件定制巨头南天公司的一伙人写的一个配置文件的解析,也是一个while循环,读取配置文件
// States
public static final int STATE_START=-14;
public static final int STATE_FIELD0=-13;
public static final int STATE_SPACE1=-12;
public static final int STATE_STATUS=-11;
public static final int STATE_URI=-10;
public static final int STATE_SPACE2=-9;
public static final int STATE_END0=-8;
public static final int STATE_END1=-7;
public static final int STATE_FIELD2=-6;
public static final int STATE_HEADER=-5;
public static final int STATE_HEADER_NAME=-4;
public static final int STATE_HEADER_IN_NAME=-3;
public static final int STATE_HEADER_VALUE=-2;
public static final int STATE_HEADER_IN_VALUE=-1;
public static final int STATE_END=0;
public static final int STATE_EOF_CONTENT=1;
public static final int STATE_CONTENT=2;
public static final int STATE_CHUNKED_CONTENT=3;
public static final int STATE_CHUNK_SIZE=4;
public static final int STATE_CHUNK_PARAMS=5;
public static final int STATE_CHUNK=6;
public static final int STATE_SEEKING_EOF=7;
通过状态位的逐渐提升,逐步完成了method,url,version,header……等一系列报文的解析
以jetty8.17版本为例:
HttpParser379行完成Method解析
HttpParser438行完成URI解析
HttpParser491行完成对AbstractHttpConnection的request信息:Method,Uri,Protoco;的注入
通过调用AbstractHttpConnection.startRequest(Buffer method, Buffer uri, Buffer version)注入三个信息
HttpParser520,522行,完成了一对Header和value的解析
HttpParser596行,完成了_hander对Header的注入
通过调用AbstractHttpConnection.parsedHeader(Buffer name, Buffer value)
在_requestFields中add(name,value)
13.2.5.4.3.1.2.6 在HttpParser644行—-》在未知response状态的情况下,假设_contentLength=HttpTokens.NO_CONTENT;(619行,原因是:如果头部既没有长度532行又没有549行chunk,就认为是没有内容的,那么就是无长度的)
进入644行_handler.headerComplete();
13.2.5.4.3.1.2.7 调用AbstractHttpConnection.headerComplete()
13.2.5.4.3.1.2.7.1 调用AbstractHttpConnection.headerComplete()
13.2.5.4.3.1.2.7.2 设置_generator.setVersion(11)代表http1.1
13.2.5.4.3.1.2.7.3 进入http1.1的switch处理分支
13.2.5.4.3.1.2.7.4 进入AbstractHttpConnection.handleRequest分支
13.2.5.4.3.1.2.7.5 AbstractHttpConnection对uri进行处理,生成path,info
13.2.5.4.3.1.2.7.6 AbstractHttpConnection调用_request.setPathInfo(info)
13.2.5.4.3.1.2.7.7 AbstractHttpConnection第494行server.handle(this);调用server方法处理AbstractHttpConnection,实现类为AsyncHttpConnection
13.2.5.4.3.1.2.7.8 Server调用public void handle(AbstractHttpConnection connection)方法
13.2.5.4.3.1.2.7.8.1 生成 target,Request,Response对象
13.2.5.4.3.1.2.7.8.2 调用Server.handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)方法
13.2.5.4.3.1.2.7.8.3 调用Server._handler.handle(target,baseRequest, request, response)
即:WebAppContext.handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)方法
……….
13.2.5.4.3.1.3 结束调用AsyncHttpConnection的父类AbstractHttpConnection的类变量_parser的parseAvailable()方法
13.2.5.4.3.1.4 调用_endp.flush(),将输出内容传输到客户端浏览器上。
——————————————————————————————————————————————————————————————
至此Jetty
服务器的启动顺序展示完毕:
上文展示了从Jetty启动、生命周期对象初始化、建立IO监听、到一个客户端发起连接、客户端输入Http报文,输入事件经各组件之间的消息传递、报文交给处理器解析执行、最终交给WebAppCOntext的Handle处理的全过程
从上文调用顺序可以看到,Jetty的模块化十分清晰,结构简单可靠,扩展性强,举个例子,如果你想用Jetty改造一下,做成一个其他协议的通讯框架,仅需在步骤13.2.5.4.3.1上扩展一个自己的Connection即可
——————————————————————————————————————————————————————————————
———————————————————————-Handle处理过程————————————————————————————-
——————————————————————————————————————————————————————————————
下文要说一下Handle处理的过程
关于Handle最好先阅读一下这两篇文章,以补充一下基础知识:
http://my.oschina.net/tryUcatchUfinallyU/blog/112972
http://www.blogjava.net/DLevin/archive/2014/05/07/413158.html
——————————————————————————————————————————————————————————————
Handler接口如下,可以看到,主要执行的是handle方法
public interface Handler extends LifeCycle, Destroyable{
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;
public void setServer(Server server);
public Server getServer();
public void destroy();
}
其子类中比较重要的有:
HandlerCollection 具有Handler的集合,可以按照顺序全部执行内部的handler
HandlerList 具有Handler的列表,按照顺序执行内部handler,如果内部发生异常或者request标记为已处理,则不再继续向下执行
HandlerWrapper 是内部一个_handler的包装,实现了HandlerContainer和LifyCycle接口,具有略微高级一点的功能。
ScopedHandler 内部有两个方法doScoped和doHandle,类文档如是说:
<p>For example if Scoped handlers A, B & C were chained together, then
the calling order would be:<pre>
A.handle(…)
A.doScope(…)
B.doScope(…)
C.doScope(…)
A.doHandle(…)
B.doHandle(…)
C.doHandle(…)
<pre>
<p>If non scoped handler X was in the chained A, B, X & C, then
the calling order would be:<pre>
A.handle(…)
A.doScope(…)
B.doScope(…)
C.doScope(…)
A.doHandle(…)
B.doHandle(…)
X.handle(…)
C.handle(…)
C.doHandle(…)
但我认为这是一个然并卵的功能:请看ScopedHandler.handle的代码:
public final void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if (_outerScope==null)
doScope(target,baseRequest,request, response);
else
doHandle(target,baseRequest,request, response);
}
public final void nextScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
if (_nextScope!=null)
_nextScope.doScope(target,baseRequest,request, response);
else if (_outerScope!=null)
_outerScope.doHandle(target,baseRequest,request, response);
else
doHandle(target,baseRequest,request, response);
}
public final void nextHandle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if (_nextScope!=null && _nextScope==_handler)
_nextScope.doHandle(target,baseRequest,request, response);
else if (_handler!=null)
_handler.handle(target,baseRequest, request, response);
}
关键在于方法中的_nextScope和_outerScope究竟是什么东西
在SocpeHandler的doStart方法中可以看到:
_outerScope就是处理序列中第一个doStart的ScopedHandle,而_nextScope是当前ScopedHandle的父类HandleWrapper的实例变量_handler
换句话说:只有用一种极其奇葩的写法,才能实现如文档说明的效果:参见http://www.blogjava.net/DLevin/archive/2014/05/07/413158.html文档
N句话总结之:
1、在实现中,其Handler链表由HandlerWrapper构建,在doStart()方法中计算_nextScope字段以及
_outerScope字段,在handle()方法中,如果_outerScope为null,则调用doScope()方法,否则调用
doHandle()方法;
2、在执行完doScope()方法后,调用nextScope()方法,该方法顺着_nextScope链表走,直到尽头,后调用doHandle()方法;
3、而doHandle()方法在完成是调用nextHandle()方法,它也沿着_nextScope链表走,只要_nextScope和
_handler相同,则调用其doHandle()方法,但是如果_nextScope和_handler不同,则调用_handler中的
handle()方法,用于处理在ScopedHandler链表中插入非ScopedHandler的情况
使用示例可以参见jetty中的testCase,也可以参照下例:
public class App003 {
public static void main(String[] args) throws Exception {
Server server = new Server();
QueuedThreadPool threadPool = new QueuedThreadPool();
threadPool.setMaxThreads(100);
server.setThreadPool(threadPool);
SelectChannelConnector selectChannelConnector = new SelectChannelConnector();
selectChannelConnector.setHost(“0.0.0.0”);
selectChannelConnector.setPort(8080);
server.addConnector(selectChannelConnector);
ScopedHandlerA sa = new ScopedHandlerA();
ScopedHandlerB sb = new ScopedHandlerB();
ScopedHandlerC sc = new ScopedHandlerC();
HandlerWrapperA ha = new HandlerWrapperA();
sa.setHandler(sb);
sb.setHandler(ha);
ha.setHandler(sc);
server.setHandler(sa);
server.start();
server.join();
}
public static class ScopedHandlerA extends ScopedHandler{
public void doScope(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“SHA-Scoped–>”);
nextScope(target, baseRequest, request, response);
System.out.println(“<–SHA-Scoped”);
}
public void doHandle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“SHA-Handle–>”);
nextHandle(target, baseRequest, request, response);
System.out.println(“<–SHA-Handle”);
}
}
public static class ScopedHandlerB extends ScopedHandler{
public void doScope(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“SHB-Scoped–>”);
nextScope(target, baseRequest, request, response);
System.out.println(“<–SHB-Scoped”);
}
public void doHandle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“SHB-Handle–>”);
nextHandle(target, baseRequest, request, response);
System.out.println(“<–SHB-Handle”);
}
}
public static class ScopedHandlerC extends ScopedHandler{
public void doScope(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“SHC-Scoped–>”);
nextScope(target, baseRequest, request, response);
System.out.println(“<–SHC-Scoped”);
}
public void doHandle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“SHC-Handle–>”);
nextHandle(target, baseRequest, request, response);
System.out.println(“<–SHC-Handle”);
}
}
public static class HandlerWrapperA extends HandlerWrapper{
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
System.out.println(“h-Handle–>”);
super.handle(target, baseRequest, request, response);
System.out.println(“<–h-Handle”);
}
}
}
执行结果如下:
SHA-Scoped–>
SHB-Scoped–>
SHC-Scoped–>
SHA-Handle–>
SHB-Handle–>
h-Handle–>
SHC-Handle–>
<–SHC-Handle
<–h-Handle
<–SHB-Handle
<–SHA-Handle
<–SHC-Scoped
<–SHB-Scoped
<–SHA-Scoped
这种写法就会形成如文档描述的效果,但我个人认为这是一个然并卵的功能:
它的优点如下:
1、可以在不同的handler之间集中执行scoped代码,例如配置加载等功能
2、可以随时选择中断不同层级的scoped运行
但缺点非常严重
1、构造方法奇特,需要对Handle,HandleWrapper,ScopedHandle等十分了解
2、逻辑比较复杂,对嵌套递归写法的熟练度要求是“必须为50%,多一点少一点都不行”,开发人员对递归的熟练度低于50%则看不懂,高于50%则会换其他的写法。
3、代码组装难懂,需要用多个HandleWrapper才能组装成Handle链,与责任链模式相比堪称四不像结构。
4、代码使用复杂,必须将handle,doScope,doHandle,nextScope,nextHandle形成正确的顺序,才可以调用成功。
换做是我,我会把三个scope和2个handler拆分成3*2+2=8个handler,直线结构的程序要比这四处乱跳的jumpto要更加稳固、更容易维护。
ContextHandle:继承自ScopedHandler,最重要的方法是doScope和doHandle
ServletContextHandler:继承自ContextHandler,重要的是重写了的ContextHandler.startContext方法
WebAppContext:继承自ServletContextHandler,重要的是实现了web应用支持的doStart,和从ContextHandle中继承来的doHandle方法。
——————————————————————————————————————————————————————————————
—————————————————————————— 伟大的分割线—————————————————————————————-
——————————————————————————————————————————————————————————————
Jetty服务器的启动、初始化、事件触发、组件消息传送、Handler处理就说到这儿。
以上内容是Jetty的核心部分,其他的附加组件如ajp、annotations、deploy、等都是从这个基础上扩展而来的。
大家如果有深入学习Jetty的需要,最好直接翻看代码,比看文档要好懂的多。