首页 > 其他 > 详细

Tomcat源码阅读之Container与Pipeline的设计

时间:2014-03-08 04:48:56      阅读:539      评论:0      收藏:0      [点我收藏+]

还是继续看Tomcat的源码吧,前面分析过了在tomcat中比较重要的一个东西Connector部分。。。

先来看一张图:

bubuko.com,布布扣


可以将tomcat的结构大概这样描述吧:

(1)sever对象是service对象的容器,

(2)service对象是connector对象和container对象的容器,同一个service对象可以包含多个connector对象,但是只能包含一个container对象。。。

(3)container对象是属于自包含的,自己又可以包含多个子container对象,

(4)同时container对象包含一个pipeline对象,pipeline对象可以理解为是valve对象的容器。。。

这里先来贴一下container接口的实现吧:

//主要是定义了父子container的管理以及pipeline的管理
public interface Container extends Lifecycle {

	//一些基本的事件的定义
    public static final String ADD_CHILD_EVENT = "addChild";  //添加了child的事件

    public static final String ADD_VALVE_EVENT = "addValve";   //在pipeline上面添加了valve的事件

    public static final String REMOVE_CHILD_EVENT = "removeChild";   //移除child的事件

    public static final String REMOVE_VALVE_EVENT = "removeValve";   //移除valve的事件

    public Log getLogger();

    //用于在jmx上面注册的名字
    public ObjectName getObjectName();

    public String getDomain();

    public String getMBeanKeyProperties();

    //pipeline,用于管理关联的values
    public Pipeline getPipeline();

    //返回关联的cluster
    public Cluster getCluster();
    public void setCluster(Cluster cluster);

    //后台运行的延迟
    public int getBackgroundProcessorDelay();
void setBackgroundProcessorDelay(int delay);

    //当前container对象的名字
    public String getName();


    public void setName(String name);

    //返回父container
    public Container getParent();

    //设置父container
    public void setParent(Container container);

    //获取父classLoader,如果当前没有的话,如果有parent那么返回parent的,否则返回applicationclassloader
    public ClassLoader getParentClassLoader();

    public void setParentClassLoader(ClassLoader parent);

    //返回realm对象,如果当前container对象没有的话,那么返回parent的realm对象
    public Realm getRealm();

    public void setRealm(Realm realm);


    // --------------------------------------------------------- Public Methods

    // 在后台执行一些周期性的工作
    public void backgroundProcess();

    //添加child对象
    public void addChild(Container child);

    // 添加listener对象,用于响应当前container对象的事件
    public void addContainerListener(ContainerListener listener);

    //添加属性改变的listener
    public void addPropertyChangeListener(PropertyChangeListener listener);

    //根据名字返回子child
    public Container findChild(String name);

    //返回所有的child
    public Container[] findChildren();

    //返回所有的containerlistener对象
    public ContainerListener[] findContainerListeners();

    //移除一个child对象
    public void removeChild(Container child);

    //移除一个containerlistener对象
    public void removeContainerListener(ContainerListener listener);

    //移除一个属性监听器
    public void removePropertyChangeListener(PropertyChangeListener listener);

    //触发容器的事件,这里主要是调度listener对象
    public void fireContainerEvent(String type, Object data);

    public void logAccess(Request request, Response response, long time,
            boolean useDefault);

    public AccessLog getAccessLog();

    //用于启动,停止子container对象的线程数量
    public int getStartStopThreads();

    //设置用于启动或者停止子container对象的线程数量
    public void setStartStopThreads(int startStopThreads);

    public File getCatalinaBase();
}

这里接口虽然还挺长的,但是实际上要做的主要的事情就是对子container对象的管理吧,例如添加或者移除子container对象。。另外就还有一些listener对象的管理了,这里分为两种listener吧,首先是事件的listener,例如添加child,添加valve事件的listener,另外就还有一种属性的listener,当属性发生改变的时候会响应。。。


好了,接下来介绍ContainerBase类型吧,先来看看它简略的继承体系吧:

bubuko.com,布布扣

这里首先是继承了LifecycleMBeanBase类型,说明对于Container对象,它的启动将会在JMX上面进行注册。。。

接着是实现了Container接口。。。

这里就不贴ContainerBase的具体实现了。。。

先来看看他的一些重要的属性定义吧:

protected final HashMap<String, Container> children = new HashMap<>();  //用于保存子container,key是子container对象的名字
protected final List<ContainerListener> listeners = new CopyOnWriteArrayList<>();  //listener,是一个写时复制的
    protected ClassLoader parentClassLoader = null;   //父classLoader


    /**
     * The Pipeline object with which this Container is associated.
     */
    protected final Pipeline pipeline = new StandardPipeline(this);   //pipeline对象
    protected final PropertyChangeSupport support =   //用于管理属性的更改情况
            new PropertyChangeSupport(this);

首先是children对象,它是hashmap类型的,用于记录当前container对象的所有的child对象,key是child的名字,value就是具体的child对象了。。。

接着是两种类型的listener,一个用于监听事件,一个用于监听属性的改变。。。这里先来看看addChild方法吧,用于添加子container对象:

    //加入child对象
    public void addChild(Container child) {
        if (Globals.IS_SECURITY_ENABLED) {
            PrivilegedAction<Void> dp =
                new PrivilegedAddChild(child);
            AccessController.doPrivileged(dp);  
        } else {
            addChildInternal(child);
        }
    }

    //加入child
    private void addChildInternal(Container child) {

        if( log.isDebugEnabled() )
            log.debug("Add child " + child + " " + this);
        synchronized(children) {
            if (children.get(child.getName()) != null)  //看是否有重名的host
                throw new IllegalArgumentException("addChild:  Child name ‘" +
                                                   child.getName() +
                                                   "‘ is not unique");
            child.setParent(this);  // May throw IAE  //设置当前child的父亲是当前对象
            children.put(child.getName(), child);  //将名字与child对应起来
        }

        // Start child
        // Don‘t do this inside sync block - start can be a slow process and
        // locking the children object can cause problems elsewhere
        if ((getState().isAvailable() ||  //如果当前已经运行了,那么启动child
                LifecycleState.STARTING_PREP.equals(getState())) &&
                startChildren) {
            try {
                child.start();  //看情况启动当前加入的child
            } catch (LifecycleException e) {
                log.error("ContainerBase.addChild: start: ", e);
                throw new IllegalStateException
                    ("ContainerBase.addChild: start: " + e);
            }
        }

        fireContainerEvent(ADD_CHILD_EVENT, child);  //激活相应的事件的listener
    }

这里还是比较简单吧,无非就是将其放入刚刚说的map里面,然后再根据当前的一些配置是否启动刚刚加入的子container对象就好了。。。接着再激活添加child的事件就好了,让相应的listener对象来响应。。。。

接下来再来看看初始化已经启动的方法吧:

    @Override
    protected void initInternal() throws LifecycleException {
        BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();   //启动,停止任务的队列
        startStopExecutor = new ThreadPoolExecutor(  //用到的executor对象
                getStartStopThreadsInternal(),
                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
                startStopQueue,
                new StartStopThreadFactory(getName() + "-startStop-"));
        startStopExecutor.allowCoreThreadTimeOut(true);
        super.initInternal();
    }


    /**
     * Start this component and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    //这里主要是启动child,还有pipeline,以及cluster对象
    protected synchronized void startInternal() throws LifecycleException {

        // Start our subordinate components, if any
        logger = null;
        getLogger();
        Cluster cluster = getClusterInternal();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        Realm realm = getRealmInternal();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();

        // Start our child containers, if any
        Container children[] = findChildren();  //获取所有的child
        List<Future<Void>> results = new ArrayList<>();
        for (int i = 0; i < children.length; i++) {   //启动所有的child
            results.add(startStopExecutor.submit(new StartChild(children[i])));
        }

        boolean fail = false;
        for (Future<Void> result : results) {
            try {
                result.get();
            } catch (Exception e) {
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
                fail = true;
            }

        }
        if (fail) {
            throw new LifecycleException(
                    sm.getString("containerBase.threadedStartFailed"));
        }

        // Start the Valves in our pipeline (including the basic), if any
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();  //启动pipeline对象


        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();  //启动background线程,执行一些周期事物

    }

这里初始化主要是在创建executor对象,比较奇怪,container对象在启动子container对象的时候并不是在当前线程中运行,而是将其派发到executor里面运行。。。

启动的方法,其实主要就是启动pipeline对象,启动所有的child,以及cluster。。。。


好啦,Container就先到这把,嗯,简单的理解为,它是container的容器,而且管理了pipeline对象。。。还有cluster啥的。。。。


好啦,接下来来看pipeline对象了。。。在具体的看它之前呢,得要先知道valve是干啥的才行。。。毕竟pipeline对象可以理解为valve对象的容器。。。。而且其的工作就是依靠valve对象来进行的。。。

那么就来看看valve接口的定义吧:

//value对象是与container相关联的处理请求的组件,一系列的value组成了pipeline
public interface Valve {

    public Valve getNext();  //返回pipeline的下一个value对象,在pipeline上面,valve对象组成了一个链表

    public void setNext(Valve valve);  //设置下一个value对象

    //执行一些周期的工作
    public void backgroundProcess();

    //处理request与response
    public void invoke(Request request, Response response)
        throws IOException, ServletException;
    //处理comet事件
    public void event(Request request, Response response, CometEvent event)
        throws IOException, ServletException;


    //是否支持异步
    public boolean isAsyncSupported();


}

嗯,这里接口的定义还算是比较的简单吧,其实说白了container对象依靠pipeline对象来处理请求,而pipeline对象则是依赖valve对象来处理请求的。。。

这里比较重要的就是invoke方法了,具体的来处理http请求。。。。

好啦,来看Pipeline接口的定义吧:

//pipeline的接口定义
public interface Pipeline {
	//返回basic的value
    public Valve getBasic();

    //这是basic的value
    public void setBasic(Valve valve);

    //在pipeline的末端添加一个value对象
    public void addValve(Valve valve);

    //返回value对象的数组
    public Valve[] getValves();

    //移除一个value对象
    public void removeValve(Valve valve);

    //获取pipeli的第一个value对象
    public Valve getFirst();

    //是否支持异步,这里如果当前pipeline上面的所有valve都支持异步才能说当前pipeline支持异步
    public boolean isAsyncSupported();

    //返回所属的container
    public Container getContainer();

    //设置container对象
    public void setContainer(Container container);

}

这里其实接口定义的还蛮简单的,接单的理解,pipeline维护了一个valve对象组成的链表,同时它还有一个特殊的valve对象,那就是basic。。。

接下来看StandardPipeline的定义吧,嗯,由于代码比较长,就不贴出来了。。来看它的重要的属性定义吧:

    /**
     * The basic Valve (if any) associated with this Pipeline.
     */
    protected Valve basic = null;   //basic的valve对象,如果有普通valve对象的话,basic对象将会处在链表的尾部


    /**
     * The Container with which this Pipeline is associated.
     */
    protected Container container = null;  //拥有这个pipeline的container对象


    /**
     * The first valve associated with this Pipeline.
     */
    protected Valve first = null;    //valve链表的头

嗯,首先是basic的valve引用,接着是当前pipeline相关联的container对象。。。最后就是说的valve链表的头部引用了。。。

这里来看几个比较基本的方法吧:

    //这里其实是启动所有的valve对象,如果它实现了lifecycle接口的话
    protected synchronized void startInternal() throws LifecycleException {

        // Start the Valves in our pipeline (including the basic), if any
        Valve current = first;
        if (current == null) {
            current = basic;
        }
        while (current != null) {
            if (current instanceof Lifecycle)
                ((Lifecycle) current).start();
            current = current.getNext();
        }

        setState(LifecycleState.STARTING);
    }

启动,其实主要是启动内部的valve对象,如果valve对象实现了lifecycle接口的话。。。

    //添加valve对象,添加到队列的尾部,但其实是在basic的前面
    public void addValve(Valve valve) {

        // Validate that we can add this Valve
        if (valve instanceof Contained)
            ((Contained) valve).setContainer(this.container);

        // Start the new component if necessary
        if (getState().isAvailable()) {
            if (valve instanceof Lifecycle) {
                try {
                    ((Lifecycle) valve).start();  //启动
                } catch (LifecycleException e) {
                    log.error("StandardPipeline.addValve: start: ", e);
                }
            }
        }

        // Add this Valve to the set associated with this Pipeline
        //如果啥都没有,那么直接first
        if (first == null) {
            first = valve;
            valve.setNext(basic);   //first后面指向basic
        } else {
            Valve current = first;
            while (current != null) {  //将这里擦到最后,然后将新插入的valve指向basic,其实basic才是队列的尾部
                if (current.getNext() == basic) {
                    current.setNext(valve);
                    valve.setNext(basic);
                    break;
                }
                current = current.getNext();
            }
        }

        container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve);
    }

这里添加valve对象的方法,主要就是将要添加的valve对象放到链表的尾部,同时要保证它的next指向basic对象。。同时有需要的话还要启动它,最后还要激活相应的container上面的事件。。。


好啦。。。到这里,container以及pipeline基本的东西就算是介绍的差不多了吧。。。


接下来就可以继续深入这部分的类容了。。。

Tomcat源码阅读之Container与Pipeline的设计,布布扣,bubuko.com

Tomcat源码阅读之Container与Pipeline的设计

原文:http://blog.csdn.net/fjslovejhl/article/details/20713005

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!