IThaiのブログ

IT関連の話題やタイに関する様々なことを書いていきます。

Tomcatのソースを読んでみる - Catalinaの開始

前回はCatalinaの初期化処理をみました。

今回はCatalinaの開始処理をみます。

public final class Bootstrap {
//----------------------------------------------中略
    /**
     * Start the Catalina daemon.
     */
    public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }

Catalina#start()を呼び出します。

   /**
     * Start a new server instance.
     */
    public void start() {

        if (getServer() == null) {
            load();
        }

        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }

        long t1 = System.nanoTime();
        
        // Start the new server
        if (getServer() instanceof Lifecycle) {
            try {
                ((Lifecycle) getServer()).start();
            } catch (LifecycleException e) {
                log.error("Catalina.start: ", e);
            }
        }

( (Lifecycle) getServer() ).start()でStandardServer#start()を呼び出します。

Lifecycleインターフェースはサーバ開始・サーバ終了のメカニズムを提供するオブジェクトに共通して継承されています。

Lifecycleの継承関連はとても多いので骨が折れます。
関連クラスは以下のようになっています。
Lifecycleのサブインターフェース

Container, Context, Engine, Executor, Host, Server, Service, Wrapper

Lifecycleの継承クラス

AccessLogValve, AuthenticatorBase, BackupManager, BasicAuthenticator,
ClusterManagerBase, ClusterSingleSignOn, CombinedRealm,
CometConnectionManagerValve, Connector, ContainerBase,
CrawlerSessionManagerValve, DataSourceRealm, DeltaManager,
DigestAuthenticator, Embedded, ErrorReportValve, ExtendedAccessLogValve,
FailedContext, FileStore, FormAuthenticator, JAASMemoryLoginModule, JAASRealm,
JDBCAccessLogValve, JDBCRealm, JDBCStore, JNDIRealm, JvmRouteBinderValve,
LifecycleBase, LifecycleMBeanBase, LockOutRealm, ManagerBase, MapperListener,
MemoryRealm, NamingResources, NonLoginAuthenticator, NullRealm,
PersistentManager, PersistentManagerBase, PersistentValve, RealmBase,
RemoteAddrValve, RemoteHostValve, RemoteIpValve, ReplicatedContext,
ReplicationValve, RequestFilterValve, SemaphoreValve, SimpleTcpCluster,
SingleSignOn, SpnegoAuthenticator, SSLAuthenticator, SSLValve, StandardContext,
StandardEngine, StandardHost, StandardManager, StandardPipeline, StandardServer,
StandardService, StandardThreadExecutor, StandardWrapper, StoreBase,
StuckThreadDetectionValve, Tomcat.ExistingStandardWrapper, UserDatabaseRealm,
ValveBase, VirtualWebappLoader, WebappClassLoader, WebappLoader

今回は上記のうち、代表的なものやシーケンス図に載っているものだけみてみます。

public final class StandardServer
    implements Lifecycle, Server, MBeanRegistration 
 {
//---------------------------------------------中略
    public void start() throws LifecycleException {

        // Validate and update our current component state
        if (started) {
            log.debug(sm.getString("standardServer.start.started"));
            return;
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Services
        synchronized (services) {
            for (int i = 0; i < services.length; i++) {
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).start();
            }
        }

((Lifecycle) services[i]).start();でStandardService#start()を呼び出します。

public class StandardService
        implements Lifecycle, Service, MBeanRegistration 
 {
//---------------------------------------------中略
   public void start() throws LifecycleException {

        // Validate and update our current component state
        if (started) {
            if (log.isInfoEnabled()) {
                log.info(sm.getString("standardService.start.started"));
            }
            return;
        }
        
        if( ! initialized )
            init(); 

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
        if(log.isInfoEnabled())
            log.info(sm.getString("standardService.start.name", this.name));
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Container first
        if (container != null) {
            synchronized (container) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle) container).start();
                }
            }
        }

StandardEngine、StandardHost、ContainerBase、StandardContext、StandardPipelineをみてみます。

public class StandardEngine
    extends ContainerBase
    implements Engine {
//---------------------------------------------------------中略
    public void start() throws LifecycleException {
        // Standard container startup
        super.start();
public abstract class ContainerBase
    implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable {
//---------------------------------------------------------中略
    public synchronized void start() throws LifecycleException {

        // Validate and update our current component state
        if (started) {
            if(log.isInfoEnabled())
                log.info(sm.getString("containerBase.alreadyStarted", logName()));
            return;
        }
        
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        started = true;

        // Start our subordinate components, if any
        if ((loader != null) && (loader instanceof Lifecycle))
            ((Lifecycle) loader).start();
        logger = null;
        getLogger();
        if ((logger != null) && (logger instanceof Lifecycle))
            ((Lifecycle) logger).start();
        if ((manager != null) && (manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();
        if ((resources != null) && (resources instanceof Lifecycle))
            ((Lifecycle) resources).start();

        // Start our child containers, if any
        Container children[] = findChildren();
        for (int i = 0; i < children.length; i++) {
            if (children[i] instanceof Lifecycle)
                ((Lifecycle) children[i]).start();
        }

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

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(START_EVENT, null);

        // Start our thread
        threadStart();

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }

ContainerBaseは抽象クラスで、継承クラスの開始処理を行っているみたいです。

public class StandardHost extends ContainerBase implements Host  {
    public synchronized void start() throws LifecycleException {
        if( started ) {
            return;
        }
        if( ! initialized )
            init();

        // Look for a realm - that may have been configured earlier. 
        // If the realm is added after context - it'll set itself.
        if( realm == null ) {
            ObjectName realmName=null;
            try {
                realmName=new ObjectName( domain + ":type=Realm,host=" + getName());
                if( mserver.isRegistered(realmName ) ) {
                    mserver.invoke(realmName, "init", 
                            new Object[] {},
                            new String[] {}
                    );            
                }
            } catch( Throwable t ) {
                log.debug("No realm for this host " + realmName);
            }
        }
            
        // Set error report valve
        if ((errorReportValveClass != null)
            && (!errorReportValveClass.equals(""))) {
            try {
                boolean found = false;
                if(errorReportValveObjectName != null) {
                    ObjectName[] names = 
                        ((StandardPipeline)pipeline).getValveObjectNames();
                    for (int i=0; !found && i<names.length; i++)
                        if(errorReportValveObjectName.equals(names[i]))
                            found = true ;
                    }
                    if(!found) {              
                        Valve valve = (Valve) Class.forName(errorReportValveClass)
                        .newInstance();
                        addValve(valve);
                        errorReportValveObjectName = ((ValveBase)valve).getObjectName() ;
                    }
            } catch (Throwable t) {
                log.error(sm.getString
                    ("standardHost.invalidErrorReportValveClass", 
                     errorReportValveClass), t);
            }
        }
        if(log.isDebugEnabled()) {
            if (xmlValidation)
                log.debug(sm.getString("standardHost.validationEnabled"));
            else
                log.debug(sm.getString("standardHost.validationDisabled"));
        }
        super.start();

    }
}

realm(レルム)の初期化をしています。レルムとは,同一の認証ポリシーを適用する範囲のことみたいです。 また、エラーコード別の適切なHTML出力を行うためにErrorReportValveを設定します。 StandardPipelineでvalveを登録します。

public class StandardPipeline
    implements Pipeline, Contained, Lifecycle 
 {
//----------------------------------------------------中略
    public synchronized void start() throws LifecycleException {

        // Validate and update our current component state
        if (started)
            throw new LifecycleException
                (sm.getString("standardPipeline.alreadyStarted"));

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        started = true;

        // 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();
            registerValve(current);
            current = current.getNext();
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(START_EVENT, null);

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }
public class HostConfig
    implements LifecycleListener {
    protected void deployApps() {

        File appBase = appBase();
        File configBase = configBase();
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs, and loop if additional descriptors are found
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);
        
    }
}

HostConfigでアプリをデプロイします。

長くなったので、HTTPリクエストを受け取る処理は次回にみてみます。

Tomcatハンドブック 第2版

Tomcatハンドブック 第2版