zoukankan      html  css  js  c++  java
  • jetty源码阅读总结1

    jetty启动分析
    jetty启动命令:java -jar /usr/alibaba/jetty/start.jar -Djetty.home=/usr/alibaba/jetty --ini=/home/admin/deploy/jetty/start.ini
    
    如果加上--help参数,则显示jetty启动的参数设置和配置设置,如下:
    #java -jar /usr/alibaba/jetty/start.jar -Djetty.home=/usr/alibaba/jetty --ini=/home/admin/deploy/jetty/start.ini --help
    properties={jetty.home=/usr/alibaba/install/jetty-distribution-7.2.0, path=/home/admin/deploy/jetty/lib/ext, OPTIONS=Server,ajp,ext,jmx,jsp,resources,websocket, lib=/home/admin/deploy/jetty/lib/ext}启动时所加载的配置选项。
    Usage: java -jar start.jar [options...] [properties...] [configs...]
    
      The start.jar builds a classpath and executes a main java class with
      a classloader built from that classpath.  By default the start.jar
      mechanism is configured to start the jetty server, but it can be 
      configured to start any java main class.   start.java里面会执行main.java这个类的main函数,由这个函数去读取start.conf配置,这个配置文件配置的jetty的相关环境变量和配置文件路径,以                                                 及接下来需要执行的main类。
    
    
    Command Line Options:
      --help           This help / usage information.  显示帮助信息
      
      --version        Print the version information for Jetty and
                       dependent jars, then exit.    显示jetty的版本
                       
      --list-options   List the details of each classpath OPTION  显示启动需要的options信息,包括:=Server,ajp,ext,jmx,jsp,resources,websocket等,可以自己指定jetty启动的特性选项。每个option的实现是在独立的jar里,
                                                                  这里配置上了jetty启动时就会去load这个jar包。
      
      --list-config    List the start.config file.     显示main类启动的配置,对应配置文件start.config
                                        
      --dry-run        Print the command line that the start.jar generates,
                       then exit. This may be used to generate command lines
                       when the start.ini includes -X or -D arguments.     显示用java -jar执行时的classpath路径等完整的java命令信息,在调试模式下有用 // Show Command Line to execute Jetty
                       
      --exec           Run the generated command line (see --dry-run) in 
                       a sub processes.  This can be used when start.ini
                       contains -X or -D arguments, but creates an extra
                       JVM instance.                                重新启动一个jvm进程 // Show Command Line to execute Jetty
                         
      --stop           Stop the running Jetty instance.    停止jetty进程
      
      --daemon         Start in daemon mode with stderr and stdout 
                       redirected to ${jetty.log}/start.log     是否开启守护进程模式
      
      --config=<file>  Specify an alternate start.config file.  
                       The default is the start.config file inside
                       the start.jar. The default can also be specified
                       with the START system property.  重新指定config配置的路径
      
      --ini=<file>     Load command line arguments from a file. If 
                       no --ini options are specified, then the 
                       start.ini file will be read if it exists.
                       A --ini option with no file indicates that
                       start.ini should not be read.   启动jetty进程的配置
                       
      --pre=<file>     Specify a configuration file that is to be processed
                       before any configuration files listed in start.ini    在加载start.ini里面执行的xml配置文件之前需要先加载的配置文件
    
    System Properties:   启动时可以设置jetty的系统环境变量
      These are set with a command line like "java -Dname=value ..." and are
      accessible via the java.lang.System#getProperty(String) API.
      Some key system properties are:
      
        org.eclipse.jetty.util.log.class=[class]    jetty加载的日志类
          A Low Level Jetty Logger Implementation to use
          (default: org.eclipse.jetty.util.log.Slf4jLog)
          
        org.eclipse.jetty.util.log.DEBUG=[boolean] 是否打开日志debug模式
          Debug logging for the stderr and javautil Loggers. Slf4j
          and other loggers must be separately configured for debug.
          (default: false)
          
        org.eclipse.jetty.util.log.IGNORED=[boolean]  是否打开日志的ignored模式
          Ignored exceptions are logged, independent of DEBUG settings
          (default: false)
    
        org.eclipse.jetty.util.log.SOURCE=[boolean]源代码的位置是否打印在错误日志上
          The source location of logs is logged in the stderr Logger.
          (default: false)
          
        com.sun.management.jmxremote     是否开通JMX功能
          Enable remote JMX management in Sun JVMS.
          
          
    Properties:  jetty启动的参数设置
      These are set with a command line like "java -jar start.jar name=value"
      and only affect the start mechanism.  Some of these are defined in the 
      default start.config and will not be available if another configuration
      file is used. NOTE: Not all properties are listed here:
    
        path=[directory] 
          An additional class path element to add to the started class path. Typically
          this is used to add directories of classes and/or resources
          
        lib=[directory]
          An additional library directory to add to the started class path. This must
          be a (deep) directory of jars
          
        STOP.PORT=[number]
          The port to use to stop the running Jetty server.
          Required along with STOP.KEY if you want to use the --stop option above.
          
        STOP.KEY=[alphanumeric]
          The passphrase defined to stop the server.
          Requried along with STOP.PORT if you want to use the --stop option above.
          
        DEBUG=true
          Enable debug on the start mechanism and sets the
          org.eclipse.jetty.util.log.stderr.DEBUG system property to true. 
          (default: false)
          
        OPTIONS=[option,option,...]  options列表
          Enable classpath OPTIONS. Each options represents one or more jars 
          to be added to the classpath. The options are defined in 
          the start.config file and can be listed with --help or --list-options.
          By convention, options starting with a capital letter (eg Server) 
          are aggregations of other available options. Available OPTIONS:
    
            All
            Client
            Server
            ajp
            annotations
            client
            default
            deploy
            ext
            jmx
            jndi
            jsp
            jta
            plus
            policy
            resources
            rewrite
            security
            server
            servlet
            servlets
            setuid
            webapp
            websocket
            xml
    
    
    Available Configurations:  默认配置列表
      By convention, configuration files are kept in $JETTY_HOME/etc.
      The known configuration files are:
      
        etc/jetty-ajp.xml  ajp支持配置
        etc/jetty-bio-ssl.xml  阻塞io的ssl支持
        etc/jetty-bio.xml  阻塞io
        etc/jetty-contexts.xml  contexts上下文配置支持
        etc/jetty-debug.xml  debug模式支持
        etc/jetty-deploy.xml  war部署支持
        etc/jetty-fileserver.xml  文件服务器支持
        etc/jetty-ipaccess.xml  ip过滤支持
        etc/jetty-jmx.xml   jmx支持
        etc/jetty-logging.xml  日志系统支持
        etc/jetty-plus.xml  增强功能支持  jaas jndi
        etc/jetty-policy.xml java的policy权限支持
        etc/jetty-proxy.xml  代理服务器支持
        etc/jetty-requestlog.xml   cookie log日志支持
        etc/jetty-rewrite.xml   url rewrite支持
        etc/jetty-ssl.xml   ssl支持
        etc/jetty-stats.xml  统计功能支持
        etc/jetty-testrealm.xml  配置权限登录service
        etc/jetty-webapps.xml   web app功能支持
        etc/jetty-xinetd.xml  使用inetd/xinetd配置jetty
        etc/jetty.xml   基础配置
    
    
    Defaults:  默认配置
      A start.ini file may be used to specify default arguments to start.jar,
      which are used if no command line arguments are provided and override 
      the defaults in the start.config file. If --ini options are provided on 
      the command line, then start.ini will no be read. The current start.ini 
      arguments are:
    
        OPTIONS=Server,jsp,jmx,resources,websocket,ext
        etc/jetty.xml
        etc/jetty-deploy.xml
        etc/jetty-webapps.xml
        etc/jetty-contexts.xml
        etc/jetty-testrealm.xml
    
    
    main函数启动:org.eclipse.jetty.start.main 需要配置启动参数,start.ini的路径
    config类的说明: The behaviour of Main is controlled by the <code>"org/eclipse/start/start.config
    main类调用org.eclipse.jetty.start.config去加载所有的配置和配置文件,然后通过加载org/eclipse/start/start.config,这个配置文件里面有两行:
    # The main class to run
    org.eclipse.jetty.xml.XmlConfiguration.class
    ${start.class}.class                             property start.class
    
    然后main类就回反射start.config配置的这个class类去执行它的main方法,
    org.eclipse.jetty.xml.XmlConfiguration这个类就是具体解析jetty.xml等所有xml配置文件中配置,
    都是关于server类的配置,这个类通过解析所有的xml文件通过反射去生成最终的org.eclipse.jetty.server.server(这个类就是jetty的服务器最核心的类)
    
    
    
    XmlConfiguration.java的main方法代码:
       public static void main( final String[] args ) //args就是start.ini里面配置的加载的xml文件
        {
    
            AccessController.doPrivileged( new PrivilegedAction()
            {
                public Object run()
                {
                    try
                    {
    
                        Properties properties=null;
                        
                        // Look for properties from start.jar
                        try
                        {
                            Class<?> config = XmlConfiguration.class.getClassLoader().loadClass("org.eclipse.jetty.start.Config");
                            properties=(Properties)config.getMethod("getProperties").invoke(null);
                            Log.debug("org.eclipse.jetty.start.Config properties = {}",properties); //加载config里面的环境变量
                        }
                        catch(NoClassDefFoundError e)
                        {
                            Log.ignore(e);
                        }
                        catch(ClassNotFoundException e)
                        {
                            Log.ignore(e);
                        }
                        catch(Exception e)
                        {
                            Log.warn(e);
                        }
                        
                        
                        // If no start.config properties, use clean slate
                        if (properties==null)
                            properties = new Properties();
                        
                        // 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();  //对每个配置文件进行解析,反射得到对应的反射出来的类,主要是Server这个类
                                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() ) //对每个反射出来的类,如果是实现LifeCycle,则启动对应的类,
                                    lc.start();
                            }
                        }
                    }
                    catch (AccessControlException ace)
                    {
                        ace.printStackTrace(System.err);
                    }
                    catch ( Exception e )
                    {
                        Log.warn( Log.EXCEPTION, e );
                    }
                    return null;
                }
            } );
        }
    
    LifeCycle接口:jetty的各个组件的生命周期管理的接口,
    
    
    
    
    jetty服务器的配置文件配置的都是"org.eclipse.jetty.server.Server"这个类,这个类包装了连接器,处理器,context上下文等信息,是jetty的主入口
    
    在jetty.xml等配置文件能够配置的标签为:
    <Configure id="Server" class="org.eclipse.jetty.server.Server">下面的子节点标签只能是下面列出来的几个:
             String tag = node.getTag();
                    if ("Set".equals(tag))  //通过调用server类的set方法去注入相关参数或者bean
                        set(obj, node);
                    else if ("Put".equals(tag)) //map注入时使用put方法去插入
                        put(obj, node);
                    else if ("Call".equals(tag)) //调用call的方法
                        call(obj, node);
                    else if ("Get".equals(tag))  //调用get方法,通过get取出值之后再通过Ref注入到需要的bean中
                        get(obj, node);
                    else if ("New".equals(tag))  //new一个新的对象
                        newObj(obj, node);
                    else if ("Array".equals(tag))  //new 一个Array对象
                        newArray(obj, node);
                    else if ("Ref".equals(tag))  //引用一个bean
                        refObj(obj, node);
                    else if ("Property".equals(tag))  //基本类型注入
                        propertyObj(obj, node);
                    else
                        throw new IllegalStateException("Unknown tag: " + tag);
    
    
    <Configure id="Server" class="org.eclipse.jetty.server.Server">
    
        <!-- =========================================================== -->
        <!-- configure rewrite handler                                   --> 
        <!-- =========================================================== -->
        <Get id="oldhandler" name="handler"/>
    
        <Set name="handler">
         <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
          <Set name="handler"><Ref id="oldhandler"/></Set>
    
    
        <Ref id="DeploymentManager">
              <Call name="addAppProvider">
                <Arg>
                  <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
                    <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set>
    
    
    线程池分析
    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>
    ////////////////////////////////////////////////////////
    这里能设置的属性:参见org.eclipse.jetty.util.thread.QueuedThreadPool 线程池实现
        private BlockingQueue<Runnable> _jobs;  任务队列
        private String _name;  线程池名字
        private int _maxIdleTimeMs=60000;  线程最大空闲时间 
        private int _maxThreads=254;  最大线程数
        private int _minThreads=8;  最小线程数
        private int _maxQueued=-1;  任务队列数,每个线程队列的线程容量是_minThreads,每次以_minThreads增长
        private int _priority=Thread.NORM_PRIORITY;  线程优先级
        private boolean _daemon=false; 是否以守护线程启动
        private int _maxStopTime=100;  服务停止时 让还在运行的线程还能运行的最长时间,在doStop()中使用 单位毫秒
    
        ....
           dostart()方法中
            if (_jobs==null)
            {
                _jobs=_maxQueued>0 ?new ArrayBlockingQueue<Runnable>(_maxQueued)
                    :new BlockingArrayQueue<Runnable>(_minThreads,_minThreads);
            }
        ....
       
       ThreadPool可以用以下三种实现:
       http://daizuan.iteye.com/blog/1114372
    
    QueuedThreadPool 使用jdk1.5的并发包得特性(AtomicInteger,ConcurrentLinkedQueue)来实现
    ExecutorThreadPool 使用jdk1.5自带的ThreadPoolExecutor
    OldQueuedThreadPool 功能跟QueuedThreadPool类似,但是实现是用加锁等jdk1.5以前已有的特性去实现,性能应该不如QueuedThreadPool
    
    ////////////////////////////////////////////////////////
          </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="8080"/></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>
    
      //////////////////////////////////////////////////////////////////////////////
    
    Connector分析: 
    
    
    
    AbstractConnector.java能够设置的参数:
     private String _host;
        private int _port = 0;
        private String _integralScheme = HttpSchemes.HTTPS; 加密协议
        private int _integralPort = 0;  加密端口
        private String _confidentialScheme = HttpSchemes.HTTPS; 信任协议
        private int _confidentialPort = 0;  信任端口
        private int _acceptQueueSize = 0; backlog 请求等待队列长度
        private int _acceptors = 1;  等待请求连接的线程数
        private int _acceptorPriorityOffset = 0;  连接器线程的优先级 current.setPriority(old_priority - _acceptorPriorityOffset);
        private boolean _useDNS;   是否使用DNS查找主机名,主机名会带入request中
        private boolean _forwarded; //是否把请求头带入request中
        private String _hostHeader;  //请求头
        
        private String _forwardedHostHeader = "X-Forwarded-Host"; 
        private String _forwardedServerHeader = "X-Forwarded-Server"; 
        private String _forwardedForHeader = "X-Forwarded-For"; 
        private String _forwardedProtoHeader = "X-Forwarded-Proto"; 
        private boolean _reuseAddress = true;
    
        protected int _maxIdleTime = 200000;  //线程最大空闲时间
        protected int _lowResourceMaxIdleTime = -1; 在请求队列大于空闲线程时,线程的空闲时间设置
        protected int _soLingerTime = -1;  
    
        public void setStatsOn(boolean on)  是否开启统计功能
    
        /** connections to server */
        private final CounterStatistic _connectionStats = new CounterStatistic(); 
        /** requests per connection */
        private final SampleStatistic _requestStats = new SampleStatistic(); 
        /** duration of a connection */
        private final SampleStatistic _connectionDurationStats = new SampleStatistic(); 
    
    SO_LINGER选项
    1) 设置该选项:public void setSoLinger(boolean on, int seconds) throws SocketException
    2) 读取该选项:public int getSoLinger() throws SocketException
    3) SO_LINGER选项用来控制Socket关闭时的行为。
    l socket.setSoLinger(true,0):执行Socket的close()方法时,该方法也会立即返回,但底层的Socket也会立即关闭,所有未发送完的剩余数据被丢弃。
    l socket.setSoLinger(true,3600):执行Socket的close()方法时,该方法不会立即返回,而进入阻塞状态,同时,底层的Socket会尝试发送剩余的数据。只有满足以下两个条件之一,close()方法才返回:
    n 底层的Socket已经发送完所有的剩余数据。
    n 尽管底层的Socket还没有发送完所有的剩余数据,但已经阻塞了3600秒。close()方法的阻塞时间超过3600秒,也会返回,剩余未发送的数据被丢弃。
    以上两种情况内,当close()方法返回后,底层的Socket会被关闭,断开连接。
    4) setSoLinger(boolean on ,int second)方法中的seconds参数以秒为单位,而不是以毫秒为单位。
    socket用法:http://www.cnblogs.com/jerrychoi/archive/2010/04/15/1712931.html
    
        安全协议在下面两个类会被调用:
    
    
    
    在ConstraintSecurityHandler.java会根据不同的安全选项进行不同的处理
     UserDataConstraint dataConstraint = roleInfo.getUserDataConstraint();
            if (dataConstraint == null || dataConstraint == UserDataConstraint.None)
            {
                return true;
            }
            HttpConnection connection = HttpConnection.getCurrentConnection();
            Connector connector = connection.getConnector();
    
            if (dataConstraint == UserDataConstraint.Integral)
            {
                if (connector.isIntegral(request))
                    return true;
                if (connector.getConfidentialPort() > 0)
                {
                    String url = connector.getIntegralScheme() + "://" + request.getServerName() + ":" + connector.getIntegralPort() + request.getRequestURI();
                    if (request.getQueryString() != null)
                        url += "?" + request.getQueryString();
                    response.setContentLength(0);
                    response.sendRedirect(url);
                }
                else
                    response.sendError(Response.SC_FORBIDDEN,"!Integral");
    
                request.setHandled(true);
                return false;
            }
            else if (dataConstraint == UserDataConstraint.Confidential)
            {
                if (connector.isConfidential(request))
                    return true;
    
                if (connector.getConfidentialPort() > 0)
                {
                    String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort()
                            + request.getRequestURI();
                    if (request.getQueryString() != null)
                        url += "?" + request.getQueryString();
    
                    response.setContentLength(0);
                    response.sendRedirect(url);
                }
                else
                    response.sendError(Response.SC_FORBIDDEN,"!Confidential");
                
                request.setHandled(true);
                return false;
            }
    
    Connect的类图结构:
    
    
    
    
    AbstractNIOConnector 下面的SelectChannelConnector和BlockingChannelConnector是通过连接字通道来配置NIO。
    NIO跟BIO的区别:在socket连接上设置Blocking为true,表示是阻塞同步,如果为false表示异步非阻塞。
       
    BlockingChannelConnector.java
            SocketChannel channel = _acceptChannel.accept();
            channel.configureBlocking(true);
            Socket socket=channel.socket();
            configure(socket);
    
            BlockingChannelEndPoint connection=new BlockingChannelEndPoint(channel);
            connection.dispatch();
    
    SelectChannelConnector.java
          SocketChannel channel = server.accept();
                            channel.configureBlocking(false);
                            Socket socket = channel.socket();
                            configure(socket);
                            _manager.register(channel);
    
    SelectChannelConnector连接器接受到请求之后,注册到SelectorManager上,由SelectorManager的doSelect去做异步处理。异步的实现方式是采用jdk1.6的select
    机制。
    
    
    SocketConnector这个是阻塞IO的一种实现。在这个类里有说明:This Connector should only be used if NIO is not available.
    
    
    SocketConnector —— 当连接请求相对较少或者NIO特性不可用时,可以使用这个连接器; 
    BlockingChannelConnector —— 连接请求相对较少时用(要求NIO特性可用) 
    SelectChannelConnector —— 当连接请求量比较大,或者需要异步处理Ajax请求 
    SslSocketConnector —— 没有NIO特性的SSL连接器 
    SslSelectChannelConnector —— 具有NIO特性的SSL连接器 
    AJPConnector —— 提供对apache mod_jk或者mod_proxy_ajp请求的支持,它是针对AJP协议的实现。
    
    
    Handler分析:
      //////////////////////////////////////////////////////////////////////////////
    
        <!-- =========================================================== -->
        <!-- 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>
        <Call name="addBean">
          <Arg>
            <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
              <Set name="contexts">
                <Ref id="Contexts" />  //上面的contexts在这里引用
              </Set>
              <Call name="setContextAttribute">
                <Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
                <Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
              </Call>
            </New>
          </Arg>
        </Call>
        <Ref id="DeploymentManager">
              <Call name="addAppProvider">
                <Arg>
                  <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">//web应用加载器
                    <Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set> //web应用加载目录配置
                    <Set name="defaultsDescriptor"><Property name="jetty.home" default="."/>/etc/webdefault.xml</Set>//web应用默认配置
                    <Set name="scanInterval">1</Set> //热部署扫描间隔 单位:秒
                    <Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set> //context配置文件路径
                    <Set name="extractWars">false</Set> //是否解压war包
                  </New>
                </Arg>
              </Call>
        </Ref>
    </Configure>
    
       /////////////////////////////////////////////////////////////////////
    
    
    
    处理器组件主要用于处理已经接收到的请求。它的主要API是一个处理函数: 
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException 
    参数说明: 
    target —— 请求的目标,通常是一个URI,或者一个资源名称。有点类似于Servlet的名字。 
    baseRequest —— 未被封装的请求对象 
    request —— 可能是Request对象(Jetty的HttpServletRequest实现),或者是一个封装过的请求。用户可以通过使用HttpConnection.getCurrentConnection()方法来访问Request对象。 
    response —— Response对象(Jetty的HttpServletResponse实现),或者是一个封装过的响应。用户可以通过使用HttpConnection.getCurrentConnection()方法来访问Request对象。
    
    一个Handler实现可以直接处理请求,或者将请求转发给其它的Handler(如Servlet等),也可以对请求中包含的数据进行修改后再转发。根据处理器的功能,可以分为三类: 
    1.路由处理器 – 这类处理器的主要作用是将请求进行路由,转发至合适的处理器进行处理,常用的有HandlerCollection, ContextHandlerCollection 
    2.过滤器 – 对请求的数据进行分析处理,然后再转发给其它处理器。如HandlerWrapper, ContextHandler, SessionHandler 
    3.处理器 – 这类处理器就是Servlet之类的了,它主要的功能是业务逻辑处理,并返回用户请求的数据。如ResourceHandler, ServletHandler。 
    
    Handler的类图结构:
      
    
    Handler主要有介绍下面几个:
    HandlerCollection.java: Handler集合,按照list的顺序执行。
         public class HandlerCollection extends AbstractHandlerContainer
        {
           private final boolean _mutableWhenRunning;  默认为false,可以通过构造函数传入。如果为true,则在启动后不能再增加handler。
           private volatile Handler[] _handlers;  handler集合,通过配置文件注入
           private boolean _parallelStart=true;   可以通过配置文件改变,如果为true,等需要等待所有handler启动完成之后才算启动完成。
        
        这里用到java并发包得countdownwatch。
                if (_parallelStart)
                {
                    final CountDownLatch latch = new CountDownLatch(_handlers.length);
                    for (int i=0;i<_handlers.length;i++)
                    {
                        final int h=i;
                        getServer().getThreadPool().dispatch(
                                new Runnable()
                                {
                                    public void run()
                                    {
                                        try{_handlers[h].start();}
                                        catch(Throwable e){mex.add(e);}
                                        finally{latch.countDown();}
                                    }
                                }
                        );
    
                    }
                    latch.await();
                }
                else
                {
                    for (int i=0;i<_handlers.length;i++)
                    {
                        try{_handlers[i].start();}
                        catch(Throwable e){mex.add(e);}
                    }
                }
    
     ContextHandlerCollection.java  由DeployManager.java的org.eclipse.jetty.deploy.providers.WebAppProvide类扫描monitoredDir属性下面的war包后,创建WebAppContext,put到
         ContextHandlerCollection的handler集合中,WebAppContext是处理J2ee标准下得war包应用的。
           
    
    
    
            Context是一种特殊的处理器(Handler),它的主要功能是将一组处理同一URI路径上的请求的处理器组织起来。一般的Context实现都会具备以下功能: 
            1.上下文路径 —— 用于标识哪些请求会被该上下文处理,如”/myapp” 
            2.静态资源路径 —— 或者说是Web应用的路径 如/www/WebRoot 
            3.类加载器 —— 用于加载分配至该Context的类,如/www/WebRoot/WEB-INF/classes
    
            Jetty中的Context实现有 
            1.ContextHandler 
            2.ServletContext 
            3.WebApplicationContext
    
            Web应用的上下文是通过使用web.xml描述文件将安全处理器(SecurityHandler)、会话处理器(SessionHandler)、Servlet等处理器组织在一起的。
    
    DefaultHandler.java:处理没有被上面其他的handler处理的请求,包括favicon.ico,404页面,OPTIONS and TRACE methods
        boolean _serveIcon=true; 是否显示服务器的icon
        boolean _showContexts=true; 如果RequestURI不是/,如果这个值为true,则显示应用的context信息,
    
    DebugHandler.java 调试模式下打印request和response的信息
          <New id="DebugHandler" class="org.eclipse.jetty.server.handler.DebugHandler">
            <Set name="handler"><Ref id="oldhandler"/></Set>
            <Set name="outputStream">
              <New class="org.eclipse.jetty.util.RolloverFileOutputStream">
                <Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
                <Arg type="boolean">true</Arg> <!-- append -->
                <Arg type="int">90</Arg> <!-- retain days -->
              </New>
            </Set>
    
    RequestLogHandler.java 打印request路径的handler
    
                   <Call name="addHandler">
            <Arg>
              <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
                     <Set name="requestLog">
                     <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
                        <Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set>
                                 <Set name="filenameDateFormat">yyyy_MM_dd</Set>
                                  <Set name="retainDays">90</Set>
                                 <Set name="append">true</Set>
                                  <Set name="extended">false</Set>
                                   <Set name="logCookies">false</Set>
                                   <Set name="LogTimeZone">GMT</Set>
                                   </New>
                         </Set>
                   </New>
            </Arg>
          </Call>
    
    IPAccessHandler.java 配置应用访问的ip白名单和黑名单
            public class IPAccessHandler extends HandlerWrapper
            {
                IPAddressMap<PathMap> _white = new IPAddressMap<PathMap>();
                IPAddressMap<PathMap> _black = new IPAddressMap<PathMap>();
             配置如下:
             <New id="IPAccessHandler" class="org.eclipse.jetty.server.handler.IPAccessHandler">
                  <Set name="handler"><Ref id="oldhandler"/></Set>
                  <Set name="white">
                    <Array type="String">
                      <Item>127.0.0.1</Item>
                      <Item>127.0.0.2/*.html</Item>
                    </Array>
                  </Set>
                  <Set name="black">
                    <Array type="String">
                      <Item>127.0.0.1/blacklisted</Item>
                      <Item>127.0.0.2/black.html</Item>
                    </Array>
                  </Set>
    
    RewriteHandler.java 配置rewrite规则的handler,详细见
    public class RewriteHandler extends HandlerWrapper
    {
        
        private RuleContainer _rules;
    
     配置如下:
         <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
          <Set name="handler"><Ref id="oldhandler"/></Set>
          <Set name="rewriteRequestURI">true</Set>
          <Set name="rewritePathInfo">false</Set>
          <Set name="originalPathAttribute">requestedPath</Set>
    
          <!-- Add rule to protect against IE ssl bug -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.MsieSslRule"/>
            </Arg>
          </Call>
    
          <!-- protect favicon handling -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
                <Set name="pattern">/favicon.ico</Set>
                <Set name="name">Cache-Control</Set>
                <Set name="value">Max-Age=3600,public</Set>
                <Set name="terminating">true</Set>
              </New>
            </Arg>
          </Call>
    
          <!-- redirect from the welcome page to a specific page -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
                <Set name="pattern">/rewrite/</Set>
                <Set name="replacement">/rewrite/info.html</Set>
              </New>
            </Arg>
          </Call>
    
          <!-- replace the entire request URI -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
                <Set name="pattern">/some/old/context</Set>
                <Set name="replacement">/rewritten/newcontext</Set>
              </New>
            </Arg>
          </Call>
    
          <!-- replace the beginning of the request URI -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
                <Set name="pattern">/rewrite/for/*</Set>
                <Set name="replacement">/rewritten/</Set>
              </New>
            </Arg>
          </Call>
          
          <!-- reverse the order of the path sections -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.RewriteRegexRule">
                <Set name="regex">(.*?)/reverse/([^/]*)/(.*)</Set>
                <Set name="replacement">$1/reverse/$3/$2</Set>
              </New>
            </Arg>
          </Call>
    
          <!-- add a cookie to each path visited -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.CookiePatternRule">
                <Set name="pattern">/*</Set>
                <Set name="name">visited</Set>
                <Set name="value">yes</Set>
              </New>
            </Arg>
          </Call>
          
          <!--  actual redirect, instead of internal rewrite -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.RedirectPatternRule">
                <Set name="pattern">/redirect/*</Set>
                <Set name="location">/redirected</Set>
              </New>
            </Arg>
          </Call>
    
          <!-- add a response rule -->
          <Call name="addRule">
            <Arg>
               <New class="org.eclipse.jetty.rewrite.handler.ResponsePatternRule">
                 <Set name="pattern">/400Error</Set>
                 <Set name="code">400</Set>
                 <Set name="reason">ResponsePatternRule Demo</Set>
              </New>
            </Arg>
          </Call>
    
         </New>
        </Set>
    
    SessionHandler.java  session管理,在cookie和URI中查找  Look for a requested session ID in cookies and URI parameters,默认sessionid的key为JSESSIONID
                         有两种实现:HashSessionManager和JDBCSessionManager。前面是存放在内存的session管理,后面是基于数据库的session管理。
    StatisticsHandler.java 服务器监控统计的handler
    ConstraintSecurityHandler.java 安全验证的handler
    ErrorPageErrorHandler.java 处理出错页面的handler
    ServletHandler.java This handler does not implement the full J2EE features and is intended to be used when a full web application is not required.                           Specifically filters and request wrapping are not supported.
    
    ResourceHandler.java 资源文件处理handler
    
       /////////////////////////////////////////// /////////////////////////
     
        <!-- =========================================================== -->
        <!-- extra options                                               -->
        <!-- =========================================================== -->
        <Set name="stopAtShutdown">true</Set>    stop的时候先去把相关的lifecycle接口的实现先stop掉
        <Set name="sendServerVersion">true</Set>  是否发送jetty的版本,在HttpConnection类调用
        <Set name="sendDateHeader">true</Set>    是否发送头信息,在requestHandler调用
        <Set name="gracefulShutdown">1000</Set>   等待connect close和context shutdown之后休眠1000毫秒再stop相关的connector,handler等
    
    </Configure>
    
    
    context:
    
    
    各个子模块的学习:(待续)
    
    Deploy:
    
    rewrite:
       由RewriteHandler.java处理,在rewrite处理完之后调用上级handler去处理。
        <Configure id="Server" class="org.eclipse.jetty.server.Server">
    
        <!-- =========================================================== -->
        <!-- configure rewrite handler                                   --> 
        <!-- =========================================================== -->
        <Get id="oldhandler" name="handler"/>
    
        <Set name="handler">
         <New id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RewriteHandler">
          <Set name="handler"><Ref id="oldhandler"/></Set>
          <Set name="rewriteRequestURI">true</Set>
          <Set name="rewritePathInfo">false</Set>
          <Set name="originalPathAttribute">requestedPath</Set>
    
          <!-- Add rule to protect against IE ssl bug -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.MsieSslRule"/>
            </Arg>
          </Call>
    
          <!-- protect favicon handling -->
          <Call name="addRule">
            <Arg>
              <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
                <Set name="pattern">/favicon.ico</Set>
                <Set name="name">Cache-Control</Set>
                <Set name="value">Max-Age=3600,public</Set>
                <Set name="terminating">true</Set>
              </New>
            </Arg>
          </Call>
          ......
       rewrite规则包括:
               MsieSslRule.java修复IE6以下的bug,增加response.setHeader(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
               HeaderPatternRule.java 在request更新头字段
               RewritePatternRule.java 把确定的请求重写为另外一个url
               RewriteRegexRule.java 用正则表达式去重写url
               CookiePatternRule.java 在cookie中增加一个参数
               RedirectPatternRule.java 重写redirect 的url
               ResponsePatternRule.java 修改response的输出
               ForwardedSchemeHeaderRule.java 重写forward的schema
    
    jmx:
    
    jndi:
      参考资料:http://baike.baidu.com/view/209575.htm
      http://blog.csdn.net/lovingprince/article/details/6364767
    
    OSGI:
    
    security:
    
       对应handler:ConstraintSecurityHandler.java继承自SecurityHandler.java抽象类
       JDBCLoginService.java默认实现
       验证方式:了解了这几种验证的代码实现 都继承子LoginAuthenticator.java抽象类,这个抽象类实现Authenticator.java这个接口,采用适配器模式
           BasicAuthenticator.java    
           ClientCertAuthenticator.java
           DigestAuthenticator.java
           FormAuthenticator.java
    
       在SecurityHandler.java的生命周期方法dostart()时,会根据配置从factory中获得对应的验证器
         if (_authenticator==null && _authenticatorFactory!=null && _identityService!=null)
            {
                _authenticator=_authenticatorFactory.getAuthenticator(getServer(),ContextHandler.getCurrentContext(),this, _identityService, _loginService);
                if (_authenticator!=null)
                    _authMethod=_authenticator.getAuthMethod();
            }
    
        对应的DefaultAuthenticatorFactory.java工厂方法中的处理:
        public Authenticator getAuthenticator(Server server, ServletContext context, AuthConfiguration configuration, IdentityService identityService,                                                  LoginService loginService)
        {
            String auth=configuration.getAuthMethod();
            Authenticator authenticator=null;
            
            if (auth==null || Constraint.__BASIC_AUTH.equalsIgnoreCase(auth))
                authenticator=new BasicAuthenticator();
            else if (Constraint.__DIGEST_AUTH.equalsIgnoreCase(auth))
                authenticator=new DigestAuthenticator();
            else if (Constraint.__FORM_AUTH.equalsIgnoreCase(auth))
                authenticator=new FormAuthenticator();
            if (Constraint.__CERT_AUTH.equalsIgnoreCase(auth)||Constraint.__CERT_AUTH2.equalsIgnoreCase(auth))
                authenticator=new ClientCertAuthenticator();
            
            return authenticator;
        }
    
    policy:
    
    servlet:
    
    servlets:
        servlet中的Filter部分
             CGI.java 处理cgi请求的,
                       主要处理:通过分析请求得到执行的CGI脚本,使用java的exec执行脚本后把输出copy到serlvetoutputstream,需要准备相关的环境变量
                       Process p=(dir==null)?Runtime.getRuntime().exec(execCmd,env.getEnvArray()):Runtime.getRuntime().exec(execCmd,env.getEnvArray(),dir);
             CloseableDoSFilter.java 允许通过jettyAPI去关闭请求连接
             DoSFilter.java  防止dos攻击的filter。只要通过限制每秒最大处理请求数,每个请求最长处理时间,以及通过ip和端口去方式dos攻击。
             ConcatServlet.java 可以在参数里面设置多个资源合并一次下载。
                                <script type="text/javascript" src="../concat?/js/behaviour.js&/js/ajax.js&/chat/chat.js"></script>
            处理代码:
            String[] parts = q.split("\\&");......
            if (type!=null)
                resp.setContentType(type);
    
            for (int i=0;i<parts.length;i++)
            {
                RequestDispatcher dispatcher=_context.getRequestDispatcher(parts[i]);
                if (dispatcher!=null)
                    dispatcher.include(req,resp);
            }
           CrossOriginFilter.java: 跨域请求合法性处理   http://hi.baidu.com/aullik5/blog/item/12f2f8ec552da74878f0553f.html
                                   通过在配置文件中配置允许跨域请求的域allowedOrigins(默认都允许)来验证来自请求头Origin这个字段是否在合法性域中,并且还可                                 以配置允许请求方法(默认为get,put)和请求的允许头字段allowedHeaders(默认= "X-Requested-With,Content-Type,Accept";)来                                  进行跨域请求处理。
           GzipFilter.java gzip压缩支持  通过对ServletOutputStream进行GZIPOutputStream装饰进行压缩支持。
           MultiPartFilter.java 文件上传支持
           ProxyServlet.java  代理serlvet支持  通过HttpExchange.java实现,注意代理serlvet有几个头字段:               
                    // Proxy headers
                    exchange.setRequestHeader("Via","1.1 (jetty)");
                    if (!xForwardedFor)
                    {
                        exchange.addRequestHeader("X-Forwarded-For",
                                request.getRemoteAddr());
                        exchange.addRequestHeader("X-Forwarded-Proto",
                                request.getScheme());
                        exchange.addRequestHeader("X-Forwarded-Host",
                                request.getServerName());
                        exchange.addRequestHeader("X-Forwarded-Server",
                                request.getLocalName());
                    }
          PutFilter.java A Filter that handles PUT, DELETE and MOVE methods.  实现简单,就是文件操作
          QoSFilter.java 限制服务进程处理的同时处理请求的数量,保证正在处理的请求的服务质量,保证服务器负载正常。
                         通过信号量Semaphore来处理最大的请求数量,新请求进来,如果请求队列中未达到正在处理的最大请求数量,则获得信号量处理当前请求,否则挂                        起当前请求,知道能获得信号量。
          UserAgentFilter.java UserAgent缓存处理,快速匹配当前的Agent放入到request.setAttribute(_attribute,ua);
          WelcomeFilter.java 如果没有配置welcome page的话可以使用这个filter。
                            String path=((HttpServletRequest)request).getServletPath();
                            if (welcome!=null && path.endsWith("/"))
                                request.getRequestDispatcher(path+welcome).forward(request,response);
                            else
                                chain.doFilter(request, response);
    webApp:
    
    webSocket:
       服务器端和客户端保持一个TCP的连接,需要浏览器支持,协议内容不一样,可以实现服务器推的技术。
       协议内容可以参考:http://feiyezi.iteye.com/blog/1060481 http://www.w3.org/TR/websockets/
    
    
    
    jetty相关资料链接:
    http://blog.romebuilder.com/2010/12/157/
    http://blog.csdn.net/lovingprince/article/details/6202669
    http://blog.csdn.net/lovingprince/article/details/6202859
    http://blog.csdn.net/lovingprince/article/details/6202859  请求处理过程分析

  • 相关阅读:
    Spring加载机制
    SpringMVC 请求过程
    Spring事务传播机制
    数组扩容
    hashmap 底层原和扩容机制
    spring源码
    金字塔表达方式(三)如何使得一个事情变得清晰有逻辑
    金字塔表达方式(二)如何判断事情的逻辑是否正确
    C#设计模式(3)——单例模式(Singleton)
    C#设计模式(2)——工厂模式
  • 原文地址:https://www.cnblogs.com/secbook/p/2655178.html
Copyright © 2011-2022 走看看