Jetty源码学习3-启动服务器

引言

本文主要介绍下环境准备、启动加载的配置文件的涵义和start.jar的加载原理。

环境准备

1、下载jetty-distribution-8.1.7.v20120910源码包并加入eclipse工程classpath中

2、准备一个war工程

3、拷贝到jetty的webapp目录

4、jetty源码打断点,并在jetty的start.jar目录下执行: java -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8090 -DEOS_DEBUG=true -jar start.jar,注意端口号。

5、要研究初始化可以在server的doStart断点,研究一次请求过程可以在server的handler断点。

配置文件

1、start.ini

指导jetty启动时需要加载的配置文件与顺序。

#etc/jetty-jmx.xml
etc/jetty.xml
etc/jetty-annotations.xml
# etc/jetty-ssl.xml
# etc/jetty-requestlog.xml
etc/jetty-deploy.xml
#etc/jetty-overlay.xml
etc/jetty-webapps.xml
etc/jetty-contexts.xml
etc/jetty-testrealm.xml

这些配置文件的顺序不能错,比如若是将jetty-deploy.xml置于最下面将导致jetty-webapps无法初始化的错误。简单介绍下几个配置的作用:

1)jmx.xml

去掉该注释,容器中的某些类便能在运行时受管理;比如:如果工程需要在不重启的情况下重新读取某配置文件,可以通过信号量的方式或者jmx的方式。这因为该功能管理着工程中需要被管理的类,因此置于最上方。

2)jetty.xml

这个就不解释了,该配制文件就对应了server类,管理着connection,thread pool,handler等。

3)deploy.xml

该配置文件对应于上篇博客描述的deployService,在jetty中就是deployManager,部署管理器,因此如果这玩意位置错了,下面的webapps.xml自然就报错了。

4)webapps.xml

war包的部署器,webappcontext便于基于此生产出来的。

5)contexts.xml

另一种部署器,主要是读取部署目录下的xml文件,不知道用在哪里,先略过。

2、jetty.xml

<Configure id="Server" class="org.eclipse.jetty.server.Server">

    <!-- =========================================================== -->
    <!-- Server Thread Pool                                          -->
    <!-- =========================================================== -->
    <Set name="ThreadPool">
      <!-- Default queued blocking threadpool -->
      <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="detailedDump">false</Set>
      </New>
    </Set>

    <!-- =========================================================== -->
    <!-- Set connectors                                              -->
    <!-- =========================================================== -->

    <Call name="addConnector">
      <Arg>
          <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
            <Set name="host"><Property name="jetty.host" /></Set>
            <Set name="port"><Property name="jetty.port" default="8888"/></Set>
            <Set name="maxIdleTime">300000</Set>
            <Set name="Acceptors">2</Set>
            <Set name="statsOn">false</Set>
            <Set name="confidentialPort">8443</Set>
	    <Set name="lowResourcesConnections">20000</Set>
	    <Set name="lowResourcesMaxIdleTime">5000</Set>
          </New>
      </Arg>
    </Call>

    <!-- =========================================================== -->
    <!-- Set handler Collection Structure                            --> 
    <!-- =========================================================== -->
    <Set name="handler">
      <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
        <Set name="handlers">
         <Array type="org.eclipse.jetty.server.Handler">
           <Item>
             <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
           </Item>
           <Item>
             <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
           </Item>
         </Array>
        </Set>
      </New>
    </Set>
</Configure>

可以看出默认的io为nio,hanler是server中比较核心的方法,Contexts是一个webappcontext的集合,请求进来的时候Contexts负责将请求分发给具体的app;而DefaultHandler即返回404错误页面,其实从这个handlers就可以看出来,请求会一次经过这个handler,一旦被hanlder即提交退出,直到不被handler走到了DefaultHandler里面返回404的页面。这里面其实自定义handler加载handlers的头部处理一些静态资源的访问,这样就直接绕过了应用webappcontext的访问了,加快了静态资源的处理速度。eg:RerourceHandler.

3、deploy.xml

<Configure id="Server" class="org.eclipse.jetty.server.Server">

    <Call name="addBean">
      <Arg>
        <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
          <Set name="contexts">
            <Ref id="Contexts" />
          </Set>
          <Call name="setContextAttribute">
            <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
            <Arg>.*/servlet-api-[^/]*\.jar$</Arg>
          </Call>
        </New>
      </Arg>
    </Call>
</Configure>

调用addBean方法,Ref  = contexts 即上面server中已经new出来的 ContextHandlerCollection,持有该contexts旨在注册所有由该类生产出来的一个个app(即WebAppContextHandler)

4、webapps.xml

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Ref id="DeploymentManager">
          <Call id="webappprovider" name="addAppProvider">
            <Arg>
              <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
                <Set name="monitoredDirName"><Property name="jetty.home" default="." />/webapps</Set>
                <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>
                <Set name="scanInterval">1</Set>
                <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set>
		<Set name="extractWars">true</Set>
              </New>
            </Arg>
          </Call>
    </Ref>
</Configure>

war工程的部署器,人如其名:WebAppProvider。从下面配的参数不难看出其主要功能,它主要是负责扫描目录下的war工程并生产ContextHandler(其实就是servletContext,对应于一个个app),而WebAppProvider又是受上面deployManager管理,生产出来的ContextHandler被deployManager注册到ContextHandlerCollection中。

start.jar加载原理

1、解析命令行参数

List arguments = new ArrayList();  
for (String arg1 : args)  
{  
  if ((arg1.startsWith("--ini=")) || (arg1.equals("--ini")))  
  {  
      arguments.addAll(loadStartIni(arg1.substring(6)));  
  }  
  else if (arg1.startsWith("--config="))  
  {  
    this._startConfig = arg1.substring(9);  
  }  
  else  
  {  
    arguments.add(arg1);  
  }  
}  
if (!(ini)){ arguments.addAll(0, loadStartIni(null));} 

先是解析命令行的参数,最后将ini配置文件merge起来。

2、定位加载资源并依据配置文件反射调用相应的类

// For all arguments, load properties or parse XMLs   
XmlConfiguration last = null;  
Object[] obj = new Object[args.length];  
for ( int i = 0; i < args.length; i++ )  
{  
    if ( args[i].toLowerCase().endsWith( ".properties" ) )  
    {  
        properties.load( Resource.newResource( args[i] ).getInputStream() );  
    }  
    else  
    {  
        XmlConfiguration configuration =  
            new XmlConfiguration( Resource.newResource( args[i] ).getURL() );  
        if ( last != null )  
            configuration.getIdMap().putAll( last.getIdMap() );  
        if ( properties.size() > 0 )  
            configuration.setProperties( properties );  
        obj[i] = configuration.configure();  
        last = configuration;  
    }  
}  
  
// For all objects created by XmlConfigurations, start them if they are lifecycles.  
for ( int i = 0; i < args.length; i++ )  
{  
    if ( obj[i] instanceof LifeCycle )  
    {  
        LifeCycle lc = (LifeCycle) obj[i];  
        if ( !lc.isRunning() )  
            lc.start();  
    }  
}  
分为两步,先是依据xm描述的内容依次解析xml并处理逻辑,期间会生成很多个实例,如果实例实现了LifeCycle接口再依次调用start方法,因此server就是在此被start起来了。


嵌入式Jetty的启动

Jetty源码学习3-启动服务器

很简单的有木有,该server只有一个webapp的handler,因此只能服务一个应用,而且错误页面自然也不是我们常见的404页面,虽然6000W做不了杀人机器,6000块也是可以做便宜的王太太百科全书的嘛!

你可能感兴趣的:(jetty)