Tomcat学習まとめ


Tomcatバージョン
  • 独立して導入されたTomcatバージョン-9.0.30
  • Spring bootバージョン-2.2.4.RELEASE
  • 内蔵Tomcat-embed-core-9.0.30
  • Tomcat概念の論述
    Tomcatのアーキテクチャ(Catalinaとも呼ばれる)は、精密な階層構造システムです.
  • Server-Tomcatインスタンス.Tomcatプロセスはサーバです.
  • サービス-Tomcatサービス、サービスはTomcatがサーブレットコンテナサービスを提供するユニットであり、サービスはサーバ内部にあり、1つのサーバに複数のサービスがあることができる.
  • Connector-ユーザー要求の主体は、サーブレットコンテナと外部ユーザーの交差部分であり、Connectorはサービス内にあり、1つのサービスに複数のConnectorが複数の要求を処理することができる.
  • Engine-Engineはサービス内部のサーブレットコンテナを表し、1つのサービスには1つのEngineしかありません.
  • Host-Hostは1つのサイトを表し、1つのEngineは複数のHostを持つことができる.
  • Context-Contextは1つのappアプリケーションを代表し、1つのEngineは複数のサブプロジェクトから構成され、異なるルーティングを割り当てることができる.
  • Wrapper-Wrapperはサーブレットコンテナであり、あるサーブレットを表す.
  • Container-Serviceコンテナ、上記のEngine/Host/Context/Wrapperは厳密にはContainerである.
  • Lifecycle-ライフサイクルは、関連するイベントが発生したときに関連するLifecycleListenerによって傍受され得る.
  • Global Naming Resources-グローバルな構成リソース
  • Realm-パーミッション構成;
  • Executor-リソースプール.

  • Tomcatスタンドアロン配置プロファイル
    /conf/server.xml
    
    
    
    
    
    
    
      
    
      
      
      
      
      
      
      
      
      
      
    
      
      
        
      
    
      
      
    
        
         
    
    
        
        
         
    
              
              
              
              
         
         
    
    
    
    
        
        
    
          
          
            
          
    
          
          
    
            
            
    
            
            
            
            
            
    
          
        
      
    

    Tomcat部分コンポーネントのソースコードの簡単な読み取り
    この部分の解析はtomcat−embed−coreを用いてソースコード観察を行った.
    Lifecycle
    org.apache.catalina.Lifecycleはインタフェースで、org.apache.catalina.util.LifecycleBaseはLifecycleインタフェースを実現し、Server/Service/Engine/Host/Context/WrapperなどのコンポーネントはLifecycleBaseを継承しています.つまり、これらのコンポーネントはライフサイクルイベントが発生したときにリスナーに監視されます.
    1モニタイベント
    eventはLifecycleが定義した監視可能なライフサイクルイベントである.
    //          
    public static final String BEFORE_INIT_EVENT = "before_init";
    //          
    public static final String AFTER_INIT_EVENT = "after_init";
    //      
    public static final String START_EVENT = "start";
    //       
    public static final String BEFORE_START_EVENT = "before_start";
    //       
    public static final String AFTER_START_EVENT = "after_start";
    //      
    public static final String STOP_EVENT = "stop";
    //       
    public static final String BEFORE_STOP_EVENT = "before_stop";
    //       
    public static final String AFTER_STOP_EVENT = "after_stop";
    //        
    public static final String AFTER_DESTROY_EVENT = "after_destroy";
    //       
    public static final String BEFORE_DESTROY_EVENT = "before_destroy";
    //         
    public static final String PERIODIC_EVENT = "periodic";
    //               ,  before_start   ,start   
    public static final String CONFIGURE_START_EVENT = "configure_start";
    //       ,  stop   ,after_stop   
    public static final String CONFIGURE_STOP_EVENT = "configure_stop";

    2コンポーネントステータス
    コンポーネントステータスはorg.apache.catalina.LifecycleStateで定義され、列挙クラスです.
    public enum LifecycleState {
        //   
        NEW(false, null),
        //      
        INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
        //      
        INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
        //       
        STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
        //     
        STARTING(true, Lifecycle.START_EVENT),
        //      
        STARTED(true, Lifecycle.AFTER_START_EVENT),
        //       
        STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
        //      
        STOPPING(false, Lifecycle.STOP_EVENT),
        //    
        STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
        //      
        DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
        //      
        DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
        //   
        FAILED(false, null);
        
        private final boolean available; //      ,    false 
        private final String lifecycleEvent; //           
    
    // ...
    }

    コードの内容は簡潔です.
    3 LifecycleBase
    LifecycleBaseはLifecycleの基本的な実装クラスであり、init()メソッドの例を示します.
    // LifecycleBase.class
    @Override
    public final synchronized void init() throws LifecycleException {
        //    init                new,           
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }
    
        try {
            // before_init     
            setStateInternal(LifecycleState.INITIALIZING, null, false);
            //         
            initInternal();
            // after_init     
            setStateInternal(LifecycleState.INITIALIZED, null, false);
        } catch (Throwable t) {
            handleSubClassException(t, "lifecycleBase.initFail", toString());
        }
    }

    Listenerと対話するコアメソッドは、addLifecycleListener(...)とsetStateInternal(...):
    // LifecycleBase.class
    @Override
    public void addLifecycleListener(LifecycleListener listener) {
        // lifecycleListeners            
        lifecycleListeners.add(listener);
    }
    
    // LifecycleBase.class
    //                  
    private synchronized void setStateInternal(
        LifecycleState state, Object data, boolean check) throws LifecycleException {
    
        //     
        if (log.isDebugEnabled()) {
            log.debug(sm.getString("lifecycleBase.setState", this, state));
        }
    
        //         
        if (check) {
        
            //            ,    ,      
            if (state == null) {
                invalidTransition("null");
                return;
            }
    
            //            ,     
            if (!(state == LifecycleState.FAILED ||
                (this.state == LifecycleState.STARTING_PREP 
                    && state == LifecycleState.STARTING) 
                    || (this.state == LifecycleState.STOPPING_PREP 
                    && state == LifecycleState.STOPPING) 
                    || (this.state == LifecycleState.FAILED 
                    && state == LifecycleState.STOPPING))
            ) {
                invalidTransition(state.name());
            }
        }
    
        //     
        this.state = state;
        String lifecycleEvent = state.getLifecycleEvent();
        if (lifecycleEvent != null) {
            //         
            fireLifecycleEvent(lifecycleEvent, data);
        }
    }
    
    // LifecycleBase.class
    protected void fireLifecycleEvent(String type, Object data) {
        //        ,         lifecycleEvent(...)   
        LifecycleEvent event = new LifecycleEvent(this, type, data);
        for (LifecycleListener listener : lifecycleListeners) {
            listener.lifecycleEvent(event);
        }
    }

    4 LifecycleListener
    org.apache.catalina.LifecycleListenerインタフェースが実装されているクラスはすべてListenerです.
    public interface LifecycleListener {
        public void lifecycleEvent(LifecycleEvent event);
    }

    最も簡単なorg.apache.catalina.startup.VersionLoggerListenerを例に挙げます.
    // VersionLoggerListener.class
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        // Tomcat    Listener       if          
        // Tomcat                     
        if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
            //     
            log();
        }
    }

    Spring bootにおけるサーブレットに関する構成
    Spring bootではこれに関連する構成が多く,筆者がプロジェクトでよく使う部分だけを列挙する.
    server:
      #   
      port: 8080
      # http       
      max-http-header-size: 8KB
    
      # servlet   
      servlet:
        session:
          # session     ,   30min
          timeout: 30m
          #       session,      session             
          persistent: false
          #           ,           
          # store-dir: classpath:session
    
      #    Tomcat      
      tomcat:
        #      
        max-threads: 2
        #      ,   200
        max-connections: 10
        # encode
        uri-encoding: UTF-8
        #       
        connection-timeout: 2m
        #        
        accept-count:
        #          
        max-http-form-post-size: 2MB
    
      #      http2
      http2.enabled: false
      
      
    
    spring:
      # Spring     
      http:
        encoding:
          #     
          charset: UTF-8
          enabled: true
          force: true
    
      # servlet   
      servlet:
        #       
        multipart:
          #         
          enabled: true
          #          
          max-file-size: 100MB
          # request     
          max-request-size: 100MB

    Spring boot内蔵Tomcatの起動
    Spring bootの組み込みサーバの運用では、サーブレットWebServer Factoryが使用されます.
    //   
    public interface ServletWebServerFactory {
        WebServer getWebServer(ServletContextInitializer... initializers);
    }

    具体的な実装クラスは次のとおりです.
    JettyServletWebServerFactory - eclipse jetty           
    TomcatServletWebServerFactory - apache tomcat           
    UndertowServletWebServerFactory - jboss undertow           

    この例では、Tomcatサービスパッケージがデフォルトで埋め込まれているため、Spring bootではTomcatServertWebServerFactoryが使用されます.
    // step 1
    // TomcatServletWebServerFactory.class
    @Override
    public WebServer getWebServer(ServletContextInitializer... initializers) {
        if (this.disableMBeanRegistry) {
            Registry.disableRegistry();
        }
        Tomcat tomcat = new Tomcat();
        File baseDir 
        = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
        
        // Tomcat    baseDir,                ,       log        
        tomcat.setBaseDir(baseDir.getAbsolutePath());
        //    Connector,    protocol
        Connector connector = new Connector(this.protocol);
        connector.setThrowOnFailure(true);
        //   Tomcat   service     connector,       Tomcat,   service       
        tomcat.getService().addConnector(connector);
        //       connector     
        customizeConnector(connector);
        //            tomcat.getService().addConnector(connector)        ,           set    
        tomcat.setConnector(connector);
        //    host      
        tomcat.getHost().setAutoDeploy(false);
        //    engine
        configureEngine(tomcat.getEngine());
        //         connector,     
        for (Connector additionalConnector 
            : this.additionalTomcatConnectors) {
            tomcat.getService().addConnector(additionalConnector);
        }
        
        // ServletContextInitializer      servlet      ,   servlet     context  
        //         context   ,     host  
        //    spring mvc           dispatcher servlet,             
        prepareContext(tomcat.getHost(), initializers);
        
        //     TomcatWebServer         Tomcat   
        return getTomcatWebServer(tomcat);
    }
    
    // step 2
    // TomcatServletWebServerFactory.class
    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
        return new TomcatWebServer(tomcat, getPort() >= 0);
    }
    
    // step 3
    // TomcatWebServer.class
    public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
        Assert.notNull(tomcat, "Tomcat Server must not be null");
        this.tomcat = tomcat;
        this.autoStart = autoStart;
        initialize();
    }
    
    // step 4
    // TomcatWebServer.class
    private void initialize() throws WebServerException {
        //     
        logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
        synchronized (this.monitor) {
            try {
                addInstanceIdToEngineName();
    
                //   context          
                Context context = findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource()) 
                            && Lifecycle.START_EVENT.equals(event.getType())) {
                        removeServiceConnectors();
                    }
                });
    
                //      tomcat
                this.tomcat.start();
                //             ,            
                rethrowDeferredStartupExceptions();
    
                try {
                    ContextBindings.bindClassLoader(
                        context, context.getNamingToken(), getClass().getClassLoader());
                } catch (NamingException ex) { }
                
                //        
                //    Tomcat              ,                   
                startDaemonAwaitThread();
            } catch (Exception ex) {
                stopSilently();
                destroySilently();
                throw new WebServerException("Unable to start embedded Tomcat", ex);
            }
        }
    }