今天学习了一下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的需要,最好直接翻看代码,比看文档要好懂的多。