BlueWell2

【安価即出荷】 by :202102211558558165:福音商店 48-Inch Buster 36 Moss 犬用品 Large, Dog Moss by 36 Happy Hounds Bed,-マット、プレート





  • 商品情報

    Buster Dog Bed, 36 by 48-Inch Large, Moss by Happy Hounds

    商品説明

    BlueWell2

    コードリーディング Tomcatのソースを読んでみよう リクエスト処理編その1 Tomcatの コードリーディング を行う本エントリ。
    今回はリクエストを受け取ってからServletを呼び出すまでの処理を見る
    「リクエスト処理編」となります。

    第1回: 準備編
    第2回: 起動編

    【安価即出荷】 by :202102211558558165:福音商店 48-Inch Buster 36 Moss 犬用品 Large, Dog Moss by 36 Happy Hounds Bed,-マット、プレート


    リクエストを待ち受けるConnector まずConnector関連の主要クラスにどのようなものがいるのか見てみましょう。
    簡単なクラス図のようなものを用意したのでご覧ください。
     

    AbstractEndpointの内部インターフェースであるHandlerの関連のクラスは
    すべてが内部クラスや内部インターフェースであり、
    しかも複数のクラス間で名前が同じだったり、継承後の名前も同じだったりするので
    わかりづらいかもしれませんが、よく見れば理解できるはずです。
    以下に簡単な解説を載せておきます。処理自体はこれから見ていきます。
    • AbstractEndpoint関連
      リクエストを待ち受けるためのインターフェース Acceptor と、
      リクエストがあった時のハンドリングを行うためのインターフェース Handler を持つ。
    • ProtocolHandler関連
      プロトコルごとの処理をハンドリングする。
      内部クラスとして、AbstractEndpoint.Handlerの実装クラスを持つ。
      この実装クラスはAbstractEndpointの実装クラスに渡され、
      リクエストがあった時に使用される。
      対応しているプロトコルや処理に使うAPIごとのサブクラスが存在する。
      分類としては 以下のようになっている。
      Apacheサーバーとの連携を行うか 処理に使用するAPI クラス 行う 旧来のI/O API AjpProtocol 新しいI/O※1のAPI AjpNioProtocol APR※2のAPI AjpAprProtocol 行わない 旧来のI/O API Http11Protocol 新しいI/OのAPI Http11NioProtocol APRのAPI Http11AprProtocol ※1 java.nioパッケージのAPI (ノンブロッキングI/Oの機能を使う)
      ※2 Apache Portable Runtime のこと。Apacheサーバーのライブラリ。
      APRのライブラリはTomcatに付属されていないため使用するには
      Tomcatの公式ページからdllをダウンロードするか(Windowsに限る)、
      ライブラリをビルドする必要がある。
    • Processor関連
      HTTPリクエストの内容(リクエストヘッダやリクエストラインなど)の読み込みを行う。
      リクエストの情報をオブジェクトにセットした後、Adapterのサービスを呼び出す。
      Processorの処理自体は、ProtocolHandler内に定義されているAbstractEndpoint.Handlerの
      実装クラスから呼び出される。
      Processorの実装クラスの分類は、ProtocolHandlerの実装クラスの分類と同じ。
    • Adapter
      Processorに渡されたリクエスト情報をラップしてTomcatのコンテナに渡す。
    要求を受けた後の処理 では、前回の続きから処理を見ていきましょう。
    (Apacheとの連携なし、かつ旧来のI/Oを使う場合の処理を見ます)
    public class JIoEndpoint extends AbstractEndpoint {

    protected Handler handler = null;

    protected class Acceptor extends AbstractEndpoint.Acceptor {
    @Override
    public void run() {

    while (running) {
    / ...中略
    / 要求を待ち受ける
    Socket socket = serverSocketFactory.acceptSocket(serverSocket);
    if (running && !paused && setSocketOptions(socket)) {
    / ソケットを渡して要求処理
    if (!processSocket(socket)) {
    closeSocket(socket);
    }
    } else {
    closeSocket(socket);
    福音商店のBuster,Dog,Bed,,36,by,48-Inch,Large,,Moss,by,Happy,Hounds:202102211558558165ならショッピング!ランキングや口コミも豊富なネット通販。更にお得なPayPay残高も!スマホアプリも充実で毎日どこからでも気になる商品をその場でお求めいただけます。ペット用品、生き物,犬用品,ベッド、マット、カバー,マット、プレート }
    / ...中略
    }
    state = AcceptorState.ENDED;
    }
    }

    protected boolean processSocket(Socket socket) {
    SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
    / ...中略
    / 別スレッドで処理を実行する
    getExecutor().execute(new SocketProcessor(wrapper));
    Buster Dog Bed, 36 by 48-Inch Large, Moss by Happy Hounds return true;
    }

    protected class SocketProcessor implements Runnable {

    protected SocketWrapper<Socket> socket = null;

    public SocketProcessor(SocketWrapper<Socket> socket) {
    if (socket==null) throw new NullPointerException();
    this.socket = socket;
    }

    @Override
    public void run() {
    boolean launch = false;
    synchronized (socket) {
    try {
    SocketState state = SocketState.OPEN;
    / ...中略
    if ((state != SocketState.CLOSED)) {
    if (status == null) {
    state = handler.process(socket, SocketStatus.OPEN);
    } else {
    state = handler.process(socket,status);
    }
    }
    / ...中略
    }
    }
    socket = null;
    / Finish up this request
    }

    }

    }

    AcceptorがacceptSocketで要求を受けた後は、
    Runnableの実装クラスであるSocketProcessorを別スレッドで実行しています。
    SocketProcessorはJioEndpointが持っているhandler(AbstractEndpoint.Handlerの実装クラス)の
    processを呼び出しています。
    以下で見るように、今回の例だとhandlerの実装クラスは
    Http11Protocol内のHttp11ConnectionHandlerとなります。
    public class Connector extends LifecycleMBeanBase {
    public Connector(String protocol) {
    / ...中略
    setProtocol(protocol);
    Class<?> clazz = Class.forName(protocolHandlerClassName);
    / handlerのインスタンスを生成する
    this.protocolHandler = (ProtocolHandler) clazz.newInstance();
    }
    public void setProtocol(String protocol) {
    / ...中略
    if ("HTTP/1.1".equals(protocol)) {
    / Http11Protocolをhandlerのクラスとする
    setProtocolHandlerClassName("org.apache.coyote.http11.Http11Protocol");
    }
    / ...中略
    }
    }
    public class Http11Protocol extends AbstractHttp11JsseProtocol {
    public Http11Protocol() {
    endpoint = new JIoEndpoint();
    cHandler = new Http11ConnectionHandler(this);
    / JioEndpointにHttp11ConnectionHandlerをセットする
    ((JIoEndpoint) endpoint).setHandler(cHandler);
    setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
    setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
    setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
    }
    }

    続いてHttp11ConnectionHandlerのprocessを見てみましょう。
    と言いたいところですが、processが定義されているのは、親クラスの方なので、
    親クラスAbstractConnectionHandlerの方も一緒に見ます。
    public abstract class AbstractProtocol implements ProtocolHandler,
    MBeanRegistration {

    protected abstract static class AbstractConnectionHandler
    <S,P extends AbstractProcessor<S>>
    implements AbstractEndpoint.Handler {

    public SocketState process(SocketWrapper<S> socket,
    SocketStatus status) {
    P processor = connections.remove(socket.getSocket());
    / ...中略
    socket.setAsync(false);
    try {
    / ...中略
    / processorを生成する
    if (processor == null) {
    processor = createProcessor();
    }
    / ...中略
    SocketState state = SocketState.CLOSED;
    do {
    if (processor.isAsync() || state == SocketState.ASYNC_END) {
    / ...中略
    } else if (processor.isComet()) {
    / ...中略
    } else {
    state = processor.process(socket);
    / ...中略
    }
    / ...中略
    } while (state == SocketState.ASYNC_END);

    / ...中略
    return state;
    } catch(java.net.SocketException e) {
    / ...中略
    }
    / ...中略
    return SocketState.CLOSED;
    }

    }

    protected abstract P createProcessor();

    }

    public class Http11Protocol extends AbstractHttp11JsseProtocol {

    protected static class Http11ConnectionHandler
    extends AbstractConnectionHandler<Socket, Http11Processor> implements Handler {

    @Override
    protected Http11Processor createProcessor() {
    / Http11Processorを生成する
    Http11Processor processor = new Http11Processor(
    proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint,
    proto.getMaxTrailerSize());
    / Adapterを設定する
    processor.setAdapter(proto.adapter);
    / ...中略
    return processor;
    }

    }

    }

    Processor (Http11Processor)を生成し、processを呼び出しています。
    (生成時、ProcessorがAdapterを使えるようにセットしています)
    生成されるのはHttp11Processorですが、先ほどと同じくprocessが定義されているのは
    親クラスの方なので親クラスの方を見てみましょう。
    public abstract class AbstractHttp11Processor<S> extends AbstractProcessor<S> {

    @Override
    public SocketState process(SocketWrapper<S> socketWrapper)
    throws IOException {
    RequestInfo rp = request.getRequestProcessor();
    rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

    / Setting up the I/O
    setSocketWrapper(socketWrapper);
    getInputBuffer().init(socketWrapper, endpoint);
    getOutputBuffer().init(socketWrapper, endpoint);

    / ...中略

    while (!error && keepAlive && !comet && !isAsync() &&
    !endpoint.isPaused()) {

    / Parsing the request header
    try {

    / リクエストラインの解析
    if (!getInputBuffer().parseRequestLine(keptAlive)) {
    / ...中略
    }

    if (endpoint.isPaused()) {
    / ...中略
    } else {
    / リクエストヘッダーの解析
    if (!getInputBuffer().parseHeaders()) {
    / ...中略
    }
    }
    } catch (IOException e) {
    / ...中略
    }

    if (!error) {
    try {
    / リクエストメソッドやユーザーエージェントなどの読み込み

    【安価即出荷】 by :202102211558558165:福音商店 48-Inch Buster 36 Moss 犬用品 Large, Dog Moss by 36 Happy Hounds Bed,-マット、プレート

    prepareRequest();
    } catch (Throwable t) {
    / ...中略
    }
    }

    if (!error) {
    try {
    / Adapterのserviceを呼び出す
    adapter.service(request, response);
    / ...中略
    } catch (Throwable t) {
    / ...中略
    }
    }
    / ...中略
    }
    / ...中略
    }

    }

    ここの処理では、Socketの入力ストリームを地道に読み込んで、Requestに詰め込んでいます。
    HttpServletRequestのメソッドでリクエストに関わる様々な情報(HTTPメソッドの名前とか)を
    取得できるのはこの処理のおかげです。
    (ここではまだHttpServletRequestになっていませんが)
    エラーが無ければAdapterのserviceが呼び出されます。
    public class CoyoteAdapter implements Adapter {
    @Override
    public void service(org.apache.coyote.Request req,
    org.apache.coyote.Response res)
    throws Exception {

    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request == null) {
    / リクエストやレスポンスを生成する
    request = connector.createRequest();
    request.setCoyoteRequest(req);
    response = connector.createResponse();
    response.setCoyoteResponse(res);
    / ...中略
    }
    / ...中略
    try {
    / Parse and set Catalina and configuration specific
    / request parameters
    req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
    boolean postParseSuccess = postParseRequest(req, request, res, response);
    if (postParseSuccess) {
    / Serviceのコンテナを取得してメソッドを呼び出す
    connector.getService().getContainer().getPipeline()
    .getFirst().invoke(request, response);
    / ...中略
    }
    / ...中略

    } catch (IOException e) {
    / Ignore
    } finally {
    req.getRequestProcessor().setWorkerThreadName(null);
    / Recycle the wrapper request and response
    if (!comet && !async) {
    request.recycle();
    response.recycle();
    } else {
    / Clear converters so that the minimum amount of memory
    / is used by this processor
    request.clearEncoders();
    response.clearEncoders();
    }
    }

    }
    }

    public class Connector extends LifecycleMBeanBase {
    public Request createRequest() {
    / 生成するのは org.apache.catalina.connector.Request
    Request request = new Request();
    request.setConnector(this);
    return (request);
    }
    }

    /** org.apache.catalina.connector.Request */
    public class Request implements HttpServletRequest {

    /** CoyoteパッケージのRequest(HttpServletRequestではない) */
    protected org.apache.coyote.Request coyoteRequest;

    public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) {
    this.coyoteRequest = coyoteRequest;
    inputBuffer.setRequest(coyoteRequest);
    }

    @Override
    public int getServerPort() {
    return coyoteRequest.getServerPort();
    }

    /** セッターがある? */
    public void setServerPort(int port) {
    coyoteRequest.setServerPort(port);
    }

    public HttpServletRequest getRequest() {
    if (facade == null) {
    facade = new RequestFacade(this);/ 自身を渡す
    }
    return facade;
    }

    }

    public class RequestFacade implements HttpServletRequest {

    /** 処理を委譲するRequest */
    protected Request request = null;

    【安価即出荷】 by :202102211558558165:福音商店 48-Inch Buster 36 Moss 犬用品 Large, Dog Moss by 36 Happy Hounds Bed,-マット、プレート public RequestFacade(Request request) {
    this.request = request;
    }

    @Override
    public int getServerPort() {
    return request.getServerPort();/ 委譲
    }

    }

    まず、connector.createRequest()でRequestを生成しています。
    そして生成したRequestにsetCoyoteRequestで、引数で渡されたRequestをセットしています。

    同じ名前のRequestが2つ登場しましたが、これらはパッケージが違います。

    org.apache.coyoteパッケージのRequestはHttpServletRequestの実装クラスではありません。
    片やorg.apache.catalina.connectorのRequestは上記ソースの通りHttpServletRequestの実装クラスです。

    「ああ、じゃあこのorg.apache.catalina.connector.RequestがServletに渡されるわけね」
    そう思うかもしれませんが・・・・・・

    違います!

    中を見てみると serServerPort() のようなセッターメソッドがあちこちに定義されています。
    HttpServletRequestにこのようなメソッドは存在しないので直接は呼び出せませんが、
    キャストすれば呼び出すことができます。これはマズイ。よろしくない。

    ということでRequestFacadeというラッパークラスが登場しました。
    org.apache.catalina.connector.RequestのgetRequest()で返しているやつです。
    このクラスもまたHttpServletRequestの実装クラスです。
    そしてこのクラスは、HttpServletRequestが定義しているセッター以外を持っていません。
    できる限り処理は委譲して済ませています。

    これで安心してServletにHttpServletRequestを渡すことができますね。

    さて、残りはServiceのコンテナを取得してメソッドを呼び出す処理です。
    Serviceが持ってるコンテナとは何か。前回に答えがあります。StandardEngineですね。
    そしてgetPipeline() やらgetFirst() やら invoke() といったメソッドを呼び出しています。

    次はここら辺のコードを見ていきましょう。

    次回: リクエスト処理編その2
    関連記事
    マット、プレート
    スポンサーサイト



    テーマ : プログラミング
    ジャンル : コンピュータ

    このページのトップへ
    トラックバック


    この記事にトラックバックする(FC2ブログユーザー)

    このページのトップへ
    コメントの投稿

    非公開コメント

    このページのトップへ
    このページのトップへ
    プロフィール

    Author:Kenji Suzuki
    IT技術に関するあれこれを書いているブログです。
    Pujohead Soft の方では開発したソフトを公開しています。

    最新記事
    最新コメント
    最新トラックバック
    月別アーカイブ
    カテゴリ
    未分類 (2)
    学習 (13)
    音楽 (2)
    プログラム (5)
    タグ

    プログラミング   デザインパターン   コードリーディング   bat  

    検索フォーム
    RSSリンクの表示
    リンク
    ブロとも申請フォーム

    この人とブロともになる

    QRコード
    メールフォーム

    名前:
    メール:
    件名:
    本文: