用户工具

站点工具


about_jetty_2

Jetty的那些事儿 第二章:Jetty框架组件架构

作者:陈科

联系方式:chenke1818@gmail.com

转载请说明出处:http://www.dumpcache.com/wiki/doku.php?id=about_jetty_2

上一篇中我们已经知道,框架的主类为:org.eclipse.jetty.xml.XmlConfiguration,所以我们还是先从该类的main函数还是走:

1.LifeCycle对象初始化

在初始化完Config类并加载以及完成系统参数的装载之后,就到了xml配置文件解析并初始LifeCycle对象。

// 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(Locale.ENGLISH).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)
                            {
                                Map<String, String> props = new HashMap<String, String>();
                                for (Object key : properties.keySet())
                                {
                                    props.put(key.toString(),String.valueOf(properties.get(key)));
                                }
                                configuration.getProperties().putAll(props);
                            }
                            obj[i] = configuration.configure();
                            last = configuration;
                        }
                    }

这个过程主要就是对XML配置文件的解析:

2.解析XML配置

XmlConfiguration configuration = new XmlConfiguration(Resource.newResource(args[i]).getURL());

XmlConfiguration configuration = new XmlConfiguration(Resource.newResource(args[i]).getURL());

public XmlConfiguration(URL configuration) throws SAXException, IOException
    {
        synchronized (__parser)
        {
            _url=configuration;
            setConfig(__parser.parse(configuration.toString()));
            _dtd=__parser.getDTD();
        }
    }

Jetty的XML解析是通过SAX来做解决方案的。XML解析完之后成了Node对象:

public synchronized Node parse(InputSource source) throws IOException, SAXException
    {
        _dtd=null;
        Handler handler = new Handler();
        XMLReader reader = _parser.getXMLReader();
        reader.setContentHandler(handler);
        reader.setErrorHandler(handler);
        reader.setEntityResolver(handler);
        if (LOG.isDebugEnabled())
            LOG.debug("parsing: sid=" + source.getSystemId() + ",pid=" + source.getPublicId());
        _parser.parse(source, handler);
        if (handler._error != null)
            throw handler._error;
        Node doc = (Node) handler._top.get(0);
        handler.clear();
        return doc;
    }

我们再来看下node的主要属性:

public static class Node extends AbstractList<Object>
    {
        Node _parent;//xml节点的父节点
        private ArrayList<Object> _list;//当前节点包含的子节点
        private String _tag;//节点名字
        private Attribute[] _attrs;//当前节点包含的属性列表
        private boolean _lastString = false;
        private String _path;
       ....
       ....

配置解析完之后,框架根据XML的配置进行框架本身的配置过程:

obj[i] = configuration.configure();

配置文件的格式为:

<Configure id="Server" class="org.eclipse.jetty.server.Server">
…
tagNode1
tagNode2
…
</Configure>

其中tagNode只支持以下几种名字:

String tag = node.getTag();
                    if ("Set".equals(tag))
                        set(obj,node);
                    else if ("Put".equals(tag))
                        put(obj,node);
                    else if ("Call".equals(tag))
                        call(obj,node);
                    else if ("Get".equals(tag))
                        get(obj,node);
                    else if ("New".equals(tag))
                        newObj(obj,node);
                    else if ("Array".equals(tag))
                        newArray(obj,node);
                    else if ("Ref".equals(tag))
                        refObj(obj,node);
                    else if ("Property".equals(tag))
                        propertyObj(node);
                    else
                        throw new IllegalStateException("Unknown tag: " + tag);
                }

3.jetty.xml的解析举例

由于这块代码比较多,我们以具有典型性的配置文件jetty.xml来作为例子讲解:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">

<!-- =============================================================== -->
<!-- Configure the Jetty Server                                      -->
<!--                                                                 -->
<!-- Documentation of this file format can be found at:              -->
<!-- http://wiki.eclipse.org/Jetty/Reference/jetty.xml_syntax        -->
<!--                                                                 -->
<!-- Additional configuration files are available in $JETTY_HOME/etc -->
<!-- and can be mixed in.  For example:                              -->
<!--   java -jar start.jar etc/jetty-ssl.xml                         -->
<!--                                                                 -->
<!-- See start.ini file for the default configuraton files           -->
<!-- =============================================================== -->


<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="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>

    <!-- =========================================================== -->
    <!-- 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>

    <!-- =========================================================== -->
    <!-- extra options                                               -->
    <!-- =========================================================== -->
    <Set name="stopAtShutdown">true</Set>
    <Set name="sendServerVersion">true</Set>
    <Set name="sendDateHeader">true</Set>
    <Set name="gracefulShutdown">1000</Set>
    <Set name="dumpAfterStart">false</Set>
    <Set name="dumpBeforeStop">false</Set>

</Configure>

我们一段一段来分析该文件:

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

首先会根据Configure标签初始化一个class:

Class<?> oClass = nodeClass(_root);

            String id = _root.getAttribute("id");
            Object obj = id == null?null:_configuration.getIdMap().get(id);

            if (obj == null && oClass != null)
            {
                obj = oClass.newInstance();
                _configuration.initializeDefaults(obj);
            }

            if (oClass != null && !oClass.isInstance(obj))
                throw new ClassCastException(oClass.toString());

并且存入idMap中:

public void configure(Object obj, XmlParser.Node cfg, int i) throws Exception
        {
            String id = cfg.getAttribute("id");
            if (id != null)
                _configuration.getIdMap().put(id,obj);

比如这里就初始化了:org.eclipse.jetty.server.Server,并对其做配置: 接着看:

<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函数:

private void set(Object obj, XmlParser.Node node) throws Exception
        {
            String attr = node.getAttribute("name");
            String name = "set" + attr.substring(0,1).toUpperCase(Locale.ENGLISH) + attr.substring(1);
            Object value = value(obj,node);
            Object[] arg =
            { value };

            Class<?> oClass = nodeClass(node);
            if (oClass != null)
                obj = null;
            else
                oClass = obj.getClass();

            Class<?>[] vClass =
            { Object.class };
            if (value != null)
                vClass[0] = value.getClass();

            if (LOG.isDebugEnabled())
                LOG.debug("XML " + (obj != null?obj.toString():oClass.getName()) + "." + name + "(" + value + ")");

            // Try for trivial match
            try
            {
                Method set = oClass.getMethod(name,vClass);
                set.invoke(obj,arg);
                return;
            }
            catch (IllegalArgumentException e)
            {
                LOG.ignore(e);
            }
            catch (IllegalAccessException e)
            {
                LOG.ignore(e);
            }
            catch (NoSuchMethodException e)
            {
                LOG.ignore(e);
            }

            // Try for native match
            try
            {
                Field type = vClass[0].getField("TYPE");
                vClass[0] = (Class<?>)type.get(null);
                Method set = oClass.getMethod(name,vClass);
                set.invoke(obj,arg);
                return;
            }
            catch (NoSuchFieldException e)
            {
                LOG.ignore(e);
            }
            catch (IllegalArgumentException e)
            {
                LOG.ignore(e);
            }
            catch (IllegalAccessException e)
            {
                LOG.ignore(e);
            }
            catch (NoSuchMethodException e)
            {
                LOG.ignore(e);
            }

            // Try a field
            try
            {
                Field field = oClass.getField(attr);
                if (Modifier.isPublic(field.getModifiers()))
                {
                    field.set(obj,value);
                    return;
                }
            }
            catch (NoSuchFieldException e)
            {
                LOG.ignore(e);
            }

            // Search for a match by trying all the set methods
            Method[] sets = oClass.getMethods();
            Method set = null;
            for (int s = 0; sets != null && s < sets.length; s++)
            {
                Class<?>[] paramTypes = sets[s].getParameterTypes();
                if (name.equals(sets[s].getName()) && paramTypes.length == 1)
                {

                    // lets try it
                    try
                    {
                        set = sets[s];
                        sets[s].invoke(obj,arg);
                        return;
                    }
                    catch (IllegalArgumentException e)
                    {
                        LOG.ignore(e);
                    }
                    catch (IllegalAccessException e)
                    {
                        LOG.ignore(e);
                    }

                    try
                    {
                        for (Class<?> c : __supportedCollections)
                            if (paramTypes[0].isAssignableFrom(c))
                            {
                                sets[s].invoke(obj,convertArrayToCollection(value,c));
                                return;
                            }
                    }
                    catch (IllegalAccessException e)
                    {
                        LOG.ignore(e);
                    }
                }
            }

            // Try converting the arg to the last set found.
            if (set != null)
            {
                try
                {
                    Class<?> sClass = set.getParameterTypes()[0];
                    if (sClass.isPrimitive())
                    {
                        for (int t = 0; t < __primitives.length; t++)
                        {
                            if (sClass.equals(__primitives[t]))
                            {
                                sClass = __primitiveHolders[t];
                                break;
                            }
                        }
                    }
                    Constructor<?> cons = sClass.getConstructor(vClass);
                    arg[0] = cons.newInstance(arg);
                    _configuration.initializeDefaults(arg[0]);
                    set.invoke(obj,arg);
                    return;
                }
                catch (NoSuchMethodException e)
                {
                    LOG.ignore(e);
                }
                catch (IllegalAccessException e)
                {
                    LOG.ignore(e);
                }
                catch (InstantiationException e)
                {
                    LOG.ignore(e);
                }
            }

            // No Joy
            throw new NoSuchMethodException(oClass + "." + name + "(" + vClass[0] + ")");
        }

这个函数异常处理逻辑较多,我们来仔细看看:

首先设置需要获取的value:

Object value = value(obj,node);

接着来看value函数:

private Object value(Object obj, XmlParser.Node node) throws Exception
        {
            Object value;

            // Get the type
            String type = node.getAttribute("type");

            // Try a ref lookup
            String ref = node.getAttribute("ref");
            if (ref != null)
            {
                value = _configuration.getIdMap().get(ref);
            }
            else
            {
                // handle trivial case
                if (node.size() == 0)
                {
                    if ("String".equals(type))
                        return "";
                    return null;
                }

                // Trim values
                int first = 0;
                int last = node.size() - 1;

                // Handle default trim type
                if (type == null || !"String".equals(type))
                {
                    // Skip leading white
                    Object item;
                    while (first <= last)
                    {
                        item = node.get(first);
                        if (!(item instanceof String))
                            break;
                        item = ((String)item).trim();
                        if (((String)item).length() > 0)
                            break;
                        first++;
                    }

                    // Skip trailing white
                    while (first < last)
                    {
                        item = node.get(last);
                        if (!(item instanceof String))
                            break;
                        item = ((String)item).trim();
                        if (((String)item).length() > 0)
                            break;
                        last--;
                    }

                    // All white, so return null
                    if (first > last)
                        return null;
                }

                if (first == last)
                    // Single Item value
                    value = itemValue(obj,node.get(first));
                else
                {
                    // Get the multiple items as a single string
                    StringBuilder buf = new StringBuilder();
                    for (int i = first; i <= last; i++)
                    {
                        Object item = node.get(i);
                        buf.append(itemValue(obj,item));
                    }
                    value = buf.toString();
                }
            }

            // Untyped or unknown
            if (value == null)
            {
                if ("String".equals(type))
                    return "";
                return null;
            }

            // Try to type the object
            if (type == null)
            {
                if (value instanceof String)
                    return ((String)value).trim();
                return value;
            }

            if (isTypeMatchingClass(type,String.class))
                return value.toString();

            Class<?> pClass = TypeUtil.fromName(type);
            if (pClass != null)
                return TypeUtil.valueOf(pClass,value.toString());

            if (isTypeMatchingClass(type,URL.class))
            {
                if (value instanceof URL)
                    return value;
                try
                {
                    return new URL(value.toString());
                }
                catch (MalformedURLException e)
                {
                    throw new InvocationTargetException(e);
                }
            }

            if (isTypeMatchingClass(type,InetAddress.class))
            {
                if (value instanceof InetAddress)
                    return value;
                try
                {
                    return InetAddress.getByName(value.toString());
                }
                catch (UnknownHostException e)
                {
                    throw new InvocationTargetException(e);
                }
            }

            for (Class<?> collectionClass : __supportedCollections)
            {
                if (isTypeMatchingClass(type,collectionClass))
                    return convertArrayToCollection(value,collectionClass);
            }

            throw new IllegalStateException("Unknown type " + type);
        }


如果只有一个item:

value = itemValue(obj,node.get(first));

如果有多个item:

{
                    // Get the multiple items as a single string
                    StringBuilder buf = new StringBuilder();
                    for (int i = first; i <= last; i++)
                    {
                        Object item = node.get(i);
                        buf.append(itemValue(obj,item));
                    }
                    value = buf.toString();
                }

我们再看获取item值的itemValue函数:

private Object itemValue(Object obj, Object item) throws Exception
        {
            // String value
            if (item instanceof String)
                return item;

            XmlParser.Node node = (XmlParser.Node)item;
            String tag = node.getTag();
            if ("Call".equals(tag))
                return call(obj,node);
            if ("Get".equals(tag))
                return get(obj,node);
            if ("New".equals(tag))
                return newObj(obj,node);
            if ("Ref".equals(tag))
                return refObj(obj,node);
            if ("Array".equals(tag))
                return newArray(obj,node);
            if ("Map".equals(tag))
                return newMap(obj,node);
            if ("Property".equals(tag))
                return propertyObj(node);

            if ("SystemProperty".equals(tag))
            {
                String name = node.getAttribute("name");
                String defaultValue = node.getAttribute("default");
                return System.getProperty(name,defaultValue);
            }

            if ("Env".equals(tag))
            {
                String name = node.getAttribute("name");
                String defaultValue = node.getAttribute("default");
                String value=System.getenv(name);
                return value==null?defaultValue:value;
            }

            LOG.warn("Unknown value tag: " + node,new Throwable());
            return null;
        }
    }

这里创建一个新的class:

    <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="detailedDump">false</Set>
      </New>

我们再看newObj函数:

private Object newObj(Object obj, XmlParser.Node node) throws Exception
        {
            Class<?> oClass = nodeClass(node);
            String id = node.getAttribute("id");
            int size = 0;
            int argi = node.size();
            for (int i = 0; i < node.size(); i++)
            {
                Object o = node.get(i);
                if (o instanceof String)
                    continue;
                if (!((XmlParser.Node)o).getTag().equals("Arg"))
                {
                    argi = i;
                    break;
                }
                size++;
            }

            Object[] arg = new Object[size];
            for (int i = 0, j = 0; j < size; i++)
            {
                Object o = node.get(i);
                if (o instanceof String)
                    continue;
                arg[j++] = value(obj,(XmlParser.Node)o);
            }

            if (LOG.isDebugEnabled())
                LOG.debug("XML new " + oClass);

            // Lets just try all constructors for now
            Constructor<?>[] constructors = oClass.getConstructors();
            for (int c = 0; constructors != null && c < constructors.length; c++)
            {
                if (constructors[c].getParameterTypes().length != size)
                    continue;

                Object n = null;
                boolean called = false;
                try
                {
                    n = constructors[c].newInstance(arg);
                    _configuration.initializeDefaults(n);
                    called = true;
                }
                catch (IllegalAccessException e)
                {
                    LOG.ignore(e);
                }
                catch (InstantiationException e)
                {
                    LOG.ignore(e);
                }
                catch (IllegalArgumentException e)
                {
                    LOG.ignore(e);
                }
                if (called)
                {
                    if (id != null)
                        _configuration.getIdMap().put(id,n);
                    configure(n,node,argi);
                    return n;
                }
            }

            throw new IllegalStateException("No Constructor: " + node + " on " + obj);
        }

该函数通过寻找New标签的子标签Arg的数量来判断使用哪一个构造函数,并且初始化对象。初始化成功后,继续调用:configure函数,这里将会循环调用3次set函数来初始化参数。

接着回到value函数,获取itemValue值之后,对值进行类型转换:

if (value == null)
            {
                if ("String".equals(type))
                    return "";
                return null;
            }

            // Try to type the object
            if (type == null)
            {
                if (value instanceof String)
                    return ((String)value).trim();
                return value;
            }

            if (isTypeMatchingClass(type,String.class))
                return value.toString();

            Class<?> pClass = TypeUtil.fromName(type);
            if (pClass != null)
                return TypeUtil.valueOf(pClass,value.toString());

            if (isTypeMatchingClass(type,URL.class))
            {
                if (value instanceof URL)
                    return value;
                try
                {
                    return new URL(value.toString());
                }
                catch (MalformedURLException e)
                {
                    throw new InvocationTargetException(e);
                }
            }

            if (isTypeMatchingClass(type,InetAddress.class))
            {
                if (value instanceof InetAddress)
                    return value;
                try
                {
                    return InetAddress.getByName(value.toString());
                }
                catch (UnknownHostException e)
                {
                    throw new InvocationTargetException(e);
                }
            }

            for (Class<?> collectionClass : __supportedCollections)
            {
                if (isTypeMatchingClass(type,collectionClass))
                    return convertArrayToCollection(value,collectionClass);
            }

            throw new IllegalStateException("Unknown type " + type);
        }

a)如果type为null,则直接返回值,否则执行以下逻辑

b)如果type是一些基本类型,则进行强制类型转换,具体逻辑可以看 TypeUtil。这里不再展开。

c)如果type是URL类型,则返回URL。

d)如果type是InetAddress则返回该类型

e)如果type是ArrayList.class,ArrayQueue.class,HashSet.class,Queue.class,List.class,Set.class,Collection.class这些类型,则进行初始化。

最后回到set方法,找到相应的set方法并执行。

<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>

接下来回到configure函数,进入到call方法:

private Object call(Object obj, XmlParser.Node node) throws Exception
        {
            String id = node.getAttribute("id");
            Class<?> oClass = nodeClass(node);
            if (oClass != null)
                obj = null;
            else if (obj != null)
                oClass = obj.getClass();
            if (oClass == null)
                throw new IllegalArgumentException(node.toString());

            int size = 0;
            int argi = node.size();
            for (int i = 0; i < node.size(); i++)
            {
                Object o = node.get(i);
                if (o instanceof String)
                    continue;
                if (!((XmlParser.Node)o).getTag().equals("Arg"))
                {
                    argi = i;
                    break;
                }
                size++;
            }

            Object[] arg = new Object[size];
            for (int i = 0, j = 0; j < size; i++)
            {
                Object o = node.get(i);
                if (o instanceof String)
                    continue;
                arg[j++] = value(obj,(XmlParser.Node)o);
            }

            String method = node.getAttribute("name");
            if (LOG.isDebugEnabled())
                LOG.debug("XML call " + method);

            try
            {
                Object n= TypeUtil.call(oClass,method,obj,arg);
                if (id != null)
                    _configuration.getIdMap().put(id,n);
                configure(n,node,argi);
                return n;
            }
            catch (NoSuchMethodException e)
            {
                IllegalStateException ise = new IllegalStateException("No Method: " + node + " on " + oClass);
                ise.initCause(e);
                throw ise;
            }

        }

call根据Arg标签初始化要调用的函数的参数,并执行相应函数。

总结以下,以下几个函数会继续调用configure函数:

以下几个函数会调用value函数:

value又会调用itemValue函数取非string类型的item值。

在初始化化完之后,解析去进行:

4.LifeCycle对象启动

LifeCycle对象启动过程:

for (int i = 0; i < args.length; i++)
                    {
                        if (obj[i] instanceof LifeCycle)
                        {
                            LifeCycle lc = (LifeCycle)obj[i];
                            if (!lc.isRunning())
                                lc.start();
                        }
                    }

可以看到只支持启动LifeCycle类型的对象。

其中AbstractLifeCycle实现了start和stop方法的通用逻辑,我们的子类只要实现doStart和doStop方法就好了。

//
//  ========================================================================
//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.util.component;

import java.util.concurrent.CopyOnWriteArrayList;

import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

/**
 * Basic implementation of the life cycle interface for components.
 * 
 * 
 */
public abstract class AbstractLifeCycle implements LifeCycle
{
    private static final Logger LOG = Log.getLogger(AbstractLifeCycle.class);
    public static final String STOPPED="STOPPED";
    public static final String FAILED="FAILED";
    public static final String STARTING="STARTING";
    public static final String STARTED="STARTED";
    public static final String STOPPING="STOPPING";
    public static final String RUNNING="RUNNING";
    
    private final Object _lock = new Object();
    private final int __FAILED = -1, __STOPPED = 0, __STARTING = 1, __STARTED = 2, __STOPPING = 3;
    private volatile int _state = __STOPPED;
    
    protected final CopyOnWriteArrayList<LifeCycle.Listener> _listeners=new CopyOnWriteArrayList<LifeCycle.Listener>();

    protected void doStart() throws Exception
    {
    }

    protected void doStop() throws Exception
    {
    }

    public final void start() throws Exception
    {
        synchronized (_lock)
        {
            try
            {
                if (_state == __STARTED || _state == __STARTING)
                    return;
                setStarting();
                doStart();
                setStarted();
            }
            catch (Exception e)
            {
                setFailed(e);
                throw e;
            }
            catch (Error e)
            {
                setFailed(e);
                throw e;
            }
        }
    }

    public final void stop() throws Exception
    {
        synchronized (_lock)
        {
            try
            {
                if (_state == __STOPPING || _state == __STOPPED)
                    return;
                setStopping();
                doStop();
                setStopped();
            }
            catch (Exception e)
            {
                setFailed(e);
                throw e;
            }
            catch (Error e)
            {
                setFailed(e);
                throw e;
            }
        }
    }

    public boolean isRunning()
    {
        final int state = _state;
        
        return state == __STARTED || state == __STARTING;
    }

    public boolean isStarted()
    {
        return _state == __STARTED;
    }

    public boolean isStarting()
    {
        return _state == __STARTING;
    }

    public boolean isStopping()
    {
        return _state == __STOPPING;
    }

    public boolean isStopped()
    {
        return _state == __STOPPED;
    }

    public boolean isFailed()
    {
        return _state == __FAILED;
    }

    public void addLifeCycleListener(LifeCycle.Listener listener)
    {
        _listeners.add(listener);
    }

    public void removeLifeCycleListener(LifeCycle.Listener listener)
    {
        _listeners.remove(listener);
    }
    
    public String getState()
    {
        switch(_state)
        {
            case __FAILED: return FAILED;
            case __STARTING: return STARTING;
            case __STARTED: return STARTED;
            case __STOPPING: return STOPPING;
            case __STOPPED: return STOPPED;
        }
        return null;
    }
    
    public static String getState(LifeCycle lc)
    {
        if (lc.isStarting()) return STARTING;
        if (lc.isStarted()) return STARTED;
        if (lc.isStopping()) return STOPPING;
        if (lc.isStopped()) return STOPPED;
        return FAILED;
    }

    private void setStarted()
    {
        _state = __STARTED;
        LOG.debug(STARTED+" {}",this);
        for (Listener listener : _listeners)
            listener.lifeCycleStarted(this);
    }

    private void setStarting()
    {
        LOG.debug("starting {}",this);
        _state = __STARTING;
        for (Listener listener : _listeners)
            listener.lifeCycleStarting(this);
    }

    private void setStopping()
    {
        LOG.debug("stopping {}",this);
        _state = __STOPPING;
        for (Listener listener : _listeners)
            listener.lifeCycleStopping(this);
    }

    private void setStopped()
    {
        _state = __STOPPED;
        LOG.debug("{} {}",STOPPED,this);
        for (Listener listener : _listeners)
            listener.lifeCycleStopped(this);
    }

    private void setFailed(Throwable th)
    {
        _state = __FAILED;
        LOG.warn(FAILED+" " + this+": "+th,th);
        for (Listener listener : _listeners)
            listener.lifeCycleFailure(this,th);
    }

    public static abstract class AbstractLifeCycleListener implements LifeCycle.Listener
    {
        public void lifeCycleFailure(LifeCycle event, Throwable cause) {}
        public void lifeCycleStarted(LifeCycle event) {}
        public void lifeCycleStarting(LifeCycle event) {}
        public void lifeCycleStopped(LifeCycle event) {}
        public void lifeCycleStopping(LifeCycle event) {}
    }
}

从这里可以看到Jetty的核心框架做的非常简单,就是一个LifeCycle的机制加上XML的解析,这样可以做到参数的灵活配置和插件的灵活替换。

5.jetty框架核心类图

最后,我们来看下jetty框架的核心类图:

最后我们再解释下几个部件的概念:

LifeCycle:就不在介绍了 AbstractLifeCycle:也不在解释了,前面已经见过了 AggregateLifeCycle:用于管理多个LifeCycle组件,维护了一个bean列表:

protected void doStart() throws Exception
    {
        for (Bean b:_beans)
        {
            if (b._managed && b._bean instanceof LifeCycle)
            {
                LifeCycle l=(LifeCycle)b._bean;
                if (!l.isRunning())
                    l.start();
            }
        }
        // indicate that we are started, so that addBean will start other beans added.
        _started=true;
        super.doStart();
    }

Connector:连接处理器

Handler:请求处理器

好了,本章就此结束,下一章将会介绍webapp初始化和动态检测的工作。

about_jetty_2.txt · 最后更改: 2018/10/14 15:31 (外部编辑)