Jetty:Embedded Server起動プロセス-1


前言
本稿はJetty 8.1に基づく.xバージョンでは、Jetty Embedded Serverのコアコンセプト、スレッドモデル、起動プロセスについて簡単に説明します.次のコードクリップは、Jettyソースコードのexample-jetty-embeddedモジュールのOneServeretContextから抜粋されています.java
public class OneServletContext {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);

        ServletContextHandler context = new ServletContextHandler(
        ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);

        ...
        
        // Serve some hello world servlets
        context.addServlet(new ServletHolder(new HelloServlet()),"/*");
        context.addServlet(new ServletHolder(
                new HelloServlet("Buongiorno Mondo")),"/it/*");
        context.addServlet(new ServletHolder(
                new HelloServlet("Bonjour le Monde")),"/fr/*");

        server.start();
        server.join();
    }
}

Embedded Jettyは使いやすく、数行のコードでhttp(サーブレット)インタフェースを実現できます.
  • サーバオブジェクトを作成し、リスニングするポート8080
  • を設定します.
  • サーブレットContextHandlerオブジェクト、サーブレットContextHandler"is-a"Handler(Request Handler)、サーブレットContext
  • を作成する
  • サーブレットContextHandlerをサーバ(server.setHandler)
  • に関連付ける
  • サーブレットContextHandlerにサーブレットを追加し、サーブレットHolderとして
  • .
  • サーバ
  • を起動
    コアコンセプト
    LifeCycle
    The lifecycle(ライフサイクル)interface for generic components、start(起動)、stop(停止)、isRunning、isStarted(クエリーステータス)の宣言などの方法
    AbstractLifeCycle
    LifeCycleインタフェースの抽象クラスを実装し、ライフサイクル管理のデフォルト実装を提供します.たとえば、_stateプロパティはコンポーネントステータスを保存し、start、stopのデフォルト実装を提供します.
    public final void start() throws Exception {
        //     
        synchronized (_lock) {
            try {
                //     
                if (_state == _STARTED || _state == _STARTING) {
                    return;
                }
                setStarting();
                //      start             
                doStart();
                setStarted();
            } catch (...) {
                ...
            }
        }
    }

    AggregateLifeCycle
    An AggregateLifeCycle is an LifeCycle implementation for a collection of contained beans AggregateLifeCycle AbstractLifeCycleから継承され、Beanのライフサイクルのセットを管理
    public class AggregateLifeCycle extends AbstractLifeCycle implements
        Destroyable, Dumpable {
        private final List _beans = new CopyOnWriteArrayList<>();
    
        private boolean _started = false;
    
        @Override
        protected void doStart() throws Exception {
            for (Bean b: beans) {
                if (b._managed && b._bean instanceof LifeCycle) {
                    LifeCycle l = (LefeCycle) b._bean;
                    if (!l.isRunning()) {
                        // start managed bean
                        l.start();
                    }
                }
            }
            _started =true;
            super.doStart();
        }
    }

    Server
    クラス階層
    AbstractLifeCycle
        AggregateLifeCycle
            AbstractHandler
                AbstractHandlerContainer
                    HandlerWrapper
                        Server

    ServerクラスはJettyの「顔」クラスで、以下を含む.
  • コネクタ、クライアント要求
  • を受信
  • Handler、クライアント要求
  • を処理する
  • ThreadPool、タスクスケジューリングスレッドプール
  • Serverクラスが提供する様々なset属性方法でConnector、ThreadPoolをカスタマイズできます.特に指定されていない場合、デフォルトのConnectorがSelectChannelConnector、デフォルトのThreadPoolがQueuedThreadPoolなどのデフォルトインプリメンテーションが作成されます.
    Connector
    (主な)クラス階層:
    Connector
        AbstractConnector
            AbstractNIOConnector
                SelectChannelConnector

    Connectorインタフェースとその実装クラスはクライアント要求を受信するために使用され、(HTTP/PDY)プロトコルは解析し、最終的にサーバの(Request)Handler処理要求を呼び出し、SelectChannelConnectorはサーバのデフォルトで使用されるConnectorである
    public Server(int port) {
        setServer(this);
    
        Connector connector = new SelectChannelConnector();
        connector.setPort(port);
        setConnectors(new Connector[]{ connector });
    }

    Handler
    クライアント要求を処理するためにHandlerまたはRequest Handlerと呼ばれる
    public interface Handler extends LifeCycle, Destroyable {
        ...
        void handle(String target, Request baseRequest, HttpServletRequest request,
                HttpServletResponse response);
        ...
    }

    handleメソッドの署名はすでにサーブレットサービスメソッドに近い.ここでtargetは通常、サーブレット構成ルールに基づいて特定のサーブレットを見つけてサービスメソッドを呼び出すために要求されたuriである.
    スレッドモデル
    Jetty Serverはスレッドプールを使用してクライアント要求を処理し、ThreadPoolインタフェースはスレッドプールの基本操作を定義し、ServerはデフォルトでQueuedThreadPoolクラスを使用し、必要に応じてServerを使用することができる.setThreadPoolメソッドスレッドプールの手動設定注意:Jetty 9.x線モデルは複雑だJetty 8.x比較的簡単で、コードが読みやすい~
    QueuedThreadPool
    QueuedThreadPoolクラス階層
    ThreadPool
        SizedThreadPool
            QueuedThreadPool

    スレッドプールのコア問題:
  • スレッド管理:作成、破棄など
  • を含む
  • タスク割当:モデル
  • をプッシュまたはプル
    スレッド管理
    最小スレッド数、最大スレッド数、スレッド最大アイドル時間による動的作成、スレッド破棄
    スレッドプールの初期化
    // QueuedThreadPool.java
    public class QueuedThreadPool {
        //        
        private int _maxThreads = 254;
        //        
        private int _minThreads = 8;
        
        ...
    
        @Override
        protected void doStart() throws Exception {
            ...
            int threads = _threadsStarted.get();
            //    _minThreads    
            while (isRunning() && threads < _minThreads) {
                startThread(threads);
                threads = _threadStarted.get();
            }
        }
    }

    スレッド破棄
    スレッドアイドル時間が設定したしきい値を超えるとmaxIdleTimeMs、スレッドプールのスレッド数が_より高いminThreadsの場合、スレッドはRunnable runメソッドから終了します.
    # QueuedThreadPool.java
    private Runnable _runnable = new Runnable() {
        public void run() {
            boolean shrink = false;
            ...
            try {
                Runnable job = _jobs.poll()
                while (isRunning()) {
                    // job loop:       job          
                    while (job != null && isRunning()) {
                        runJob(job);
                        job = _jobs.poll();
                    }
    
                    // idle loop
                    try {
                        _threadsIdle.incrementAndGet();
                        while (isRunning() && job == null) {
                            //    _maxIdleTimeMs < 0        ,        job
                            if (_maxIdleTimeMs <= 0) {
                                job = _jobs.take();
                            } else {
                                final int size = _threadsStarted.get();
                                //          _minThreads          
                                if (size > _minThreads) {
                                    long last = _lastShrink.get();
                                    long now = System.currentTimeMillis();
                                    if (last == 0 || (now - last) > _maxIdleTimeMs) {
                                        shrink = _lastShrink.compareAndSet(last, now) &&
                                            _threadsStarted.compareAndSet(size, size - 1);
                                        if (shringk) {
                                            //    while   ,     
                                            return;
                                        }
                                    }
                                }
                                //   timeout   poll
                                job = idleJobPoll();
                            }
                        }
                    }
                }
            } catch (...) {
            } finally {
            }
        }
    }

    タスクの割り当て
    ブロックされたキューを使用すると、ワークスレッドはブロックされたキューからアクティブにタスク(job)を引き出し、QueuedThreadPoolはデフォルトでArrayBlockingQueueを使用します.必要に応じて、ブロックされたキューの具体的な実装を構築方法で手動で指定できます.
    public class QueuedThreadPool {
        public QueuedThreadPool(BlockingQueue jobQ) {
            this();
            _jobs = jobQ;
            _jobs.clear();
        }
    
        public boolean dispatch(Runnable job) {
            if (isRunning()) {
                final int jobQ = _jobs.size();
                final int idle = getIdleThreads();
                //   job      
                if (_jobs.offer(job)) {
                    //        idle    ,          job   idle              
                    if (idle == 0 || jobQ > idle) {
                        int threads = _threadsStarted.get();
                        if (threads < _maxThreads) {
                            startThread(threads);
                        }
                    }
                    return true;
                }
            }
            return false;
        }
    }

    プロセスの開始
    サーバの起動はstartメソッドの呼び出しから始まります.前述したように、サーバクラスはAggregateServerから継承され、親クラスのstartメソッドは最終的にサーバのdoStartメソッドを呼び出します.
    Server start
    @Override
    protected void doStart() throws Exception {
        ...
        //       ThreadPool
        if (_threadPool == null) {
            setThreadPool(new QueuedThreadPool())
        }
        try {
            super.doStart();
        } catch(Throwable e) {...}
        //    Connector,  ,    
        if (_connectors != null && mex.size == 0) {
            for (int i = 0; i < _connectors.length; i++) {
                try {
                    _connectors[i].start();
                } catch (Throwable e) {
                    mex.add(e);
                }
            }
        }
        ...
    }