上一篇中我们分析了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的分析就到此。