从servlet到springboot(15) Tomcat源码分析(2)。Container和connectors

56 篇文章 2 订阅

上一篇中我们分析了tomcat启动的整体流程和管理生命周期的系列组件,这一节,我们将要分析Container和Connectors

先看下Container的类继承体系

可以看到Container有四个子类,Context Engine Wrapper Host和一个默认的实现类 ContainerBase  这些类都继承LifecycleBase接口。所以符合tomcat的生命周期管理方法,上一节也提到过

上面这张图体现了四个子类的关系,Context和Host的区别是Context表示一个应用,比如默认配置下webapps下的每个目录都是一个应用,其中ROOT目录中存放着主应用,其他目录存放着别的子应用,而整个webapps是一个站点。加入www.baidu.com域名对应着webapps目录所代表的站点,其中ROOT目录中就是主应用,访问时直接使用域名即可,而webapps/test目录存放的test子应用,访问时需要用www.baidu.com/test,每一个应用对应一个Context。所有webapps下的应用都属于www.baidu.com的站点。而blog.baidu.com是另一个站点,属于另外一个Host

 

接下去我们来分析下Container的启动过程

前面我们说过service会调用start方法,里面会调用Container和connectors的start和init方法,同样这两个方法内部也是调用模板方法initInternal和startInternal,只是不同的是Container有四个子类的默认实现类,而且Container还有一个默认实现类ContainerBase。

我们先看ContainerBase的initInternal方法

@Override
protected void initInternal() throws LifecycleException {
    BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
    startStopExecutor = new ThreadPoolExecutor(
            getStartStopThreadsInternal(),
            getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
            startStopQueue,
            new StartStopThreadFactory(getName() + "-startStop-"));
    startStopExecutor.allowCoreThreadTimeOut(true);
    super.initInternal();
}

可以看到这主要创建了线程池

再看startInternal方法

@Override
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();
    List<Future<Void>> results = new ArrayList<>();
    for (int i = 0; i < children.length; i++) {
        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();


    setState(LifecycleState.STARTING);

    // Start our thread
    threadStart();

}

这里主要做了五件事情:

如果有Cluster和Realm则调用其start方法;

Container children[] = findChildren(); List<Future<Void>> results = new ArrayList<>(); for (int i = 0; i < children.length; i++) { results.add(startStopExecutor.submit(new StartChild(children[i]))); }

这几句代码回找到所有的子容器,然后调用start方法

if (pipeline instanceof Lifecycle) ((Lifecycle) pipeline).start();这句话会启动管道,关于管道会在下一篇说明

setState(LifecycleState.STARTING); 将生命周期状态设置starting模式

Service最先调用的是最顶曾的容器Engine的init和start方法,默认的Engine实现类是StandardEngine,我们直接看这个类的initInternal和startInternal

protected void initInternal() throws LifecycleException {
    // Ensure that a Realm is present before any attempt is made to start
    // one. This will create the default NullRealm if necessary.
    getRealm();
    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
protected synchronized void startInternal() throws LifecycleException {

    // Log our server identification information
    if(log.isInfoEnabled())
        log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());

    // Standard container startup
    super.startInternal();
}

可以看到直接调用ContainerBase中的这两个方法

StandardHost这边就不说了

StandardContext的startInternal

@Override
protected synchronized void startInternal() throws LifecycleException {

。。。。。。。。

        if (ok) {
            if (!listenerStart()) {
                log.error( "Error listenerStart");
                ok = false;
            }
        }

        // Check constraints for uncovered HTTP methods
        // Needs to be after SCIs and listeners as they may programatically
        // change constraints
        if (ok) {
            checkConstraintsForUncoveredMethods(findConstraints());
        }

        。。。。。。
        if (ok) {
            if (!filterStart()) {
                log.error("Error filterStart");
                ok = false;
            }
        }

 。。。。。
        if (ok) {
            loadOnStartup(findChildren());
        }

    // Reinitializing if something went wrong
    if (!ok) {
        setState(LifecycleState.FAILED);
    } else {
        setState(LifecycleState.STARTING);
    }
}

StandardContext的startInternal方法主要读取了web.xml中配置的Linsteners,Filters,以及Servlet的配置信息,然后调用了配置的contextInitialized方法,Filter和配置了load-on-startup的Servlet的init方法

Context和Host一样,都有一个LifecycleListener类型的监听器ContextConfig,都会触发相应的事件。

最后看Standardwrapper

initInternal没有重写

startInternal中

@Override
protected synchronized void startInternal() throws LifecycleException {

    // Send j2ee.state.starting notification
    if (this.getObjectName() != null) {
        Notification notification = new Notification("j2ee.state.starting",
                                                    this.getObjectName(),
                                                    sequenceNumber++);
        broadcaster.sendNotification(notification);
    }

    // Start up this component
    super.startInternal();

    setAvailable(0L);

    // Send j2ee.state.running notification
    if (this.getObjectName() != null) {
        Notification notification =
            new Notification("j2ee.state.running", this.getObjectName(),
                            sequenceNumber++);
        broadcaster.sendNotification(notification);
    }

通过代码我们关注到这里面主要做了三件事情,

1.用broadcaster发送通知

2.调用父类的startInternal

3.调用setAvailable方法让Servlet生效

我们把Container的内容分析完了,接下去分析connectors相关内容

Connectors用于接收请求并将请求封装成Request和Response来具体处理,最底层是通过Socket来进行链接的。Req和Res封装完成后会交给Conatiner,Container交给Servlet,Servlet处理完成之后返还给Connector,最后Connector使用Socket将处理结果返回给客户端。这样整个请求就完成了

Connector中有一非常重要的一个组件ProtocalHandler,而这个组件又由Endpoint Processor Adapter三个组件组成

如下图

Endpoint中又包含Acceptor,Handler和AsyncTimeout两个内部类。Acceptor用于监听请求,AsyncTimeout用于检查异步request超时,Handler用于处理接收到的socket,内部调用Processor进行处理,然后调用Adapter的service方法进行适配,最终交给Container进行处理。

在这一篇幅中我们说过在StandardService中的initInternal中有connetors.init方法,这里会初始化connectors

初始化connectors主要就是初始化protocalHandler

在整个connector中,Endpoint是用来处理TCP/IP协议的,processor是用来处理HTTP协议的。

 

关于container和connectors的分析就到此。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值