結(jié)合 tomcat 處理流程分析 Filter 的執(zhí)行

緣起

  • 大約3-4年前看過(guò) Tomcat 的源碼醋界,那時(shí)候主要聚焦在 Tomcat 加載 war 包的過(guò)程;一個(gè)星期前的周末在研究攔截器 Filter 的過(guò)程中發(fā)現(xiàn)可以整合Tomcat的執(zhí)行流程來(lái)一并分析膳帕,所以就有了這篇文章粘捎。

  • 文章的輸出很大程度取決于日常的積累,時(shí)機(jī)到了就會(huì)有相應(yīng)的輸出危彩,基本上沒(méi)有其他更快的路徑了攒磨。


Tomcat 線程模型

  • Acceptor線程:全局唯一,負(fù)責(zé)接受請(qǐng)求汤徽,并將請(qǐng)求放入Poller線程的事件隊(duì)列娩缰。Accetpr線程在分發(fā)事件的時(shí)候,采用的Round Robin的方式來(lái)分發(fā)的

  • Poller線程:官方的建議是每個(gè)處理器配一個(gè)谒府,但不要超過(guò)兩個(gè)拼坎,由于現(xiàn)在幾乎都是多核處理器,所以一般來(lái)說(shuō)都是兩個(gè)狱掂。每個(gè)Poller線程各自維護(hù)一個(gè)事件隊(duì)列(無(wú)上限)演痒,它的職責(zé)是從事件隊(duì)列里面拿出socket,往自己的selector上注冊(cè)趋惨,然后等待selector選擇讀寫(xiě)事件鸟顺,并交給SocketProcessor線程去實(shí)際處理請(qǐng)求。

  • SocketProcessor線程池:tomcat的默認(rèn)配置是250(參見(jiàn)server.xml里面的maxThreads),它是實(shí)際的工作線程讯嫂,用于處理請(qǐng)求蹦锋。


Tomcat 執(zhí)行流程

tomcat 執(zhí)行流程


Tomcat 監(jiān)聽(tīng)過(guò)程

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {

    private NioSelectorPool selectorPool = new NioSelectorPool();
    private ServerSocketChannel serverSock = null;
    private Executor executor = null;

    public final void start() throws Exception {
        if (bindState == BindState.UNBOUND) {
            bind();
            bindState = BindState.BOUND_ON_START;
        }
        startInternal();
    }

    @Override
    public void bind() throws Exception {
        // 創(chuàng)建 serverSock 執(zhí)行綁定
        serverSock = ServerSocketChannel.open();

        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
        serverSock.socket().bind(addr,getAcceptCount());
        serverSock.configureBlocking(true); 

        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1;
        }
        if (pollerThreadCount <= 0) {
            pollerThreadCount = 1;
        }
        setStopLatch(new CountDownLatch(pollerThreadCount));
        initialiseSsl();
        selectorPool.open();
    }


    @Override
    public void startInternal() throws Exception {
        if (!running) {
            running = true;
            paused = false;

            processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getProcessorCache());
            eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            socketProperties.getEventCache());
            nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getBufferPool());

            // 創(chuàng)建 Poller 執(zhí)行任務(wù)的線程
            if ( getExecutor() == null ) {
                createExecutor();
            }

            initializeConnectionLatch();

            // 開(kāi)啟 Poller 相關(guān)的線程
            pollers = new Poller[getPollerThreadCount()];
            for (int i=0; i<pollers.length; i++) {
                pollers[i] = new Poller();
                Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
            }

            // 啟動(dòng)Acceptor線程
            startAcceptorThreads();
        }
    }

    protected final void startAcceptorThreads() {
        int count = getAcceptorThreadCount();
        acceptors = new Acceptor[count];

        for (int i = 0; i < count; i++) {
            acceptors[i] = createAcceptor();
            String threadName = getName() + "-Acceptor-" + i;
            acceptors[i].setThreadName(threadName);
            Thread t = new Thread(acceptors[i], threadName);
            t.setPriority(getAcceptorThreadPriority());
            t.setDaemon(getDaemon());
            t.start();
        }
    }


    public void createExecutor() {
        internalExecutor = true;
        TaskQueue taskqueue = new TaskQueue();
        TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
        taskqueue.setParent( (ThreadPoolExecutor) executor);
    }
}
  • Tomcat 監(jiān)聽(tīng)過(guò)程負(fù)責(zé)創(chuàng)建監(jiān)聽(tīng) socket 并進(jìn)行 bind 操作,參見(jiàn)bind()方法欧芽。
  • Tomcat 負(fù)責(zé)創(chuàng)建Poller對(duì)象并綁定對(duì)應(yīng)的Poller線程莉掂。
  • Tomcat 負(fù)責(zé)創(chuàng)建Acceptor對(duì)象并綁定對(duì)應(yīng)的Acceptor線程。
  • Tomcat 負(fù)責(zé)創(chuàng)建SocketProcessor執(zhí)行的線程池對(duì)象 Executor千扔。


Tomcat 連接處理過(guò)程

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {

    private ServerSocketChannel serverSock = null;

    protected class Acceptor extends AbstractEndpoint.Acceptor {
        @Override
        public void run() {
            while (running) {
                // 省略相關(guān)代碼
                state = AcceptorState.RUNNING;
                try {
                    SocketChannel socket = null;
                    try {
                        // 獲取新的鏈接
                        socket = serverSock.accept();
                    } catch (IOException ioe) {
                    }

                    if (running && !paused) {
                        // 通過(guò)setSocketOptions設(shè)置新連接的socket
                        if (!setSocketOptions(socket)) {
                            closeSocket(socket);
                        }
                    } 
                } catch (Throwable t) {
                }
            }
            state = AcceptorState.ENDED;
        }
    }

    protected boolean setSocketOptions(SocketChannel socket) {
        try {
            socket.configureBlocking(false);
            Socket sock = socket.socket();
            socketProperties.setProperties(sock);

            NioChannel channel = nioChannels.pop();
            if (channel == null) {
                SocketBufferHandler bufhandler = new SocketBufferHandler(
                        socketProperties.getAppReadBufSize(),
                        socketProperties.getAppWriteBufSize(),
                        socketProperties.getDirectBuffer());
                if (isSSLEnabled()) {
                    channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
                } else {
                    channel = new NioChannel(socket, bufhandler);
                }
            } else {
                channel.setIOChannel(socket);
                channel.reset();
            }
            // 注冊(cè)對(duì)應(yīng)的 Poller 當(dāng)中
            getPoller0().register(channel);
        } catch (Throwable t) {
            return false;
        }
        return true;
    }

    public Poller getPoller0() {
        int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length;
        return pollers[idx];
    }
}
  • Acceptor線程接受請(qǐng)求憎妙,從nioChannels里拿出NioChannel對(duì)象。從Poller 隊(duì)列中輪詢(xún)拿到一個(gè) Poller 后關(guān)聯(lián) NioChannel曲楚。
  • setSocketOptions的getPoller0().register(channel)負(fù)責(zé)注冊(cè) accept 的NioChannel到Poller中厘唾。

Tomcat Socket 注冊(cè)過(guò)程

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {

    public class Poller implements Runnable {

        private Selector selector;
        private final SynchronizedQueue<PollerEvent> events =
                new SynchronizedQueue<>();
        private volatile boolean close = false;
        private long nextExpiration = 0;
        private AtomicLong wakeupCounter = new AtomicLong(0);
        private volatile int keyCount = 0;

        public Poller() throws IOException {
            this.selector = Selector.open();
        }

        public void register(final NioChannel socket) {
            socket.setPoller(this);
            // 包裝 socket 成 NioSocketWrapper對(duì)象進(jìn)行處理
            NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
            socket.setSocketWrapper(ka);
            ka.setPoller(this);
            ka.setReadTimeout(getSocketProperties().getSoTimeout());
            ka.setWriteTimeout(getSocketProperties().getSoTimeout());
            ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
            ka.setSecure(isSSLEnabled());
            ka.setReadTimeout(getConnectionTimeout());
            ka.setWriteTimeout(getConnectionTimeout());
            PollerEvent r = eventCache.pop();

            // 注意對(duì)應(yīng)的事件
            ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
            if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
            else r.reset(socket,ka,OP_REGISTER);
            addEvent(r);
        }

        private void addEvent(PollerEvent event) {
            events.offer(event);
            if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
        }

        public boolean events() {
            boolean result = false;
            PollerEvent pe = null;
            while ( (pe = events.poll()) != null ) {
                result = true;
                try {
                    pe.run();
                    pe.reset();
                    if (running && !paused) {
                        eventCache.push(pe);
                    }
                } catch ( Throwable x ) {
                }
            }

            return result;
        }

        public void run() {
            while (true) {
                boolean hasEvents = false;
                try {
                    if (!close) {
                        hasEvents = events();
                    }
                } catch (Throwable x) {
                }
                // 省略代碼
            }
        }
    }


    public static class PollerEvent implements Runnable {

        private NioChannel socket;
        private int interestOps;
        private NioSocketWrapper socketWrapper;

        public PollerEvent(NioChannel ch, NioSocketWrapper w, int intOps) {
            reset(ch, w, intOps);
        }

        @Override
        public void run() {
            if (interestOps == OP_REGISTER) {
                try {
                    socket.getIOChannel().register(
                            socket.getPoller().getSelector(), SelectionKey.OP_READ, socketWrapper);
                } catch (Exception x) {
                }
            } 
        }
    }
}
  • Poller實(shí)現(xiàn)NioChannel的register過(guò)程通過(guò)PollerEvent的創(chuàng)建和提交來(lái)實(shí)現(xiàn)。
  • Poller的 run 方法中會(huì)調(diào)用PollerEvent的 run 方法龙誊,進(jìn)而實(shí)現(xiàn)NioChannel的注冊(cè)抚垃。


Tomcat Socket 任務(wù)處理過(guò)程

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {
    public class Poller implements Runnable {
        @Override
        public void run() {
            while (true) {
                // 省略代碼
                Iterator<SelectionKey> iterator =
                    keyCount > 0 ? selector.selectedKeys().iterator() : null;

                while (iterator != null && iterator.hasNext()) {
                    SelectionKey sk = iterator.next();
                    NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();

                    if (attachment == null) {
                        iterator.remove();
                    } else {
                        iterator.remove();
                        // 處理連接請(qǐng)求
                        processKey(sk, attachment);
                    }
                }
                timeout(keyCount,hasEvents);
            }
        }

        protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
            try {
                if ( close ) {
                    cancelledKey(sk);
                } else if ( sk.isValid() && attachment != null ) {
                    if (sk.isReadable() || sk.isWritable() ) {
                        if ( attachment.getSendfileData() != null ) {
                            processSendfile(sk,attachment, false);
                        } else {
                            unreg(sk, attachment, sk.readyOps());
                            boolean closeSocket = false;
                            if (sk.isReadable()) {
                                // 處理可讀事件
                                if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
                                    closeSocket = true;
                                }
                            }
                        }
                    }
                } 
            }  catch (Throwable t) {
            }
        }
    }

    public boolean processSocket(SocketWrapperBase<S> socketWrapper,
            SocketEvent event, boolean dispatch) {
        try {
            if (socketWrapper == null) {
                return false;
            }
            // SocketProcessor對(duì)象
            SocketProcessorBase<S> sc = processorCache.pop();
            if (sc == null) {
                sc = createSocketProcessor(socketWrapper, event);
            } else {
                sc.reset(socketWrapper, event);
            }
            Executor executor = getExecutor();
            if (dispatch && executor != null) {
                // 執(zhí)行對(duì)應(yīng)的連接請(qǐng)求
                executor.execute(sc);
            } else {
                sc.run();
            }
        } catch (RejectedExecutionException ree) {
            return false;
        } catch (Throwable t) {
            return false;
        }
        return true;
    }
}
  • Poller注冊(cè)NioChannel后通過(guò) select 方法返回待處理的NioSocketWrapper對(duì)象,進(jìn)而包裝成SocketProcessor后提交Executor 進(jìn)行處理趟大。


Tomcat 請(qǐng)求處理過(guò)程

public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {

   protected class SocketProcessor extends SocketProcessorBase<NioChannel> {

        public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
            super(socketWrapper, event);
        }

        @Override
        protected void doRun() {
            NioChannel socket = socketWrapper.getSocket();
            SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());

            try {
                int handshake = -1;

                // 省略代碼

                if (handshake == 0) {
                    SocketState state = SocketState.OPEN;
                    // 通過(guò)ConnectionHandler 處理請(qǐng)求
                    if (event == null) {
                        state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                    } else {
                        state = getHandler().process(socketWrapper, event);
                    }
                    if (state == SocketState.CLOSED) {
                        close(socket, key);
                    }
                } 
            } catch (Throwable t) {
            } finally {
            }
        }
    }
}
  • SocketProcessor作為封裝任務(wù)內(nèi)部?jī)H執(zhí)行ConnectionHandler的 proces 方法鹤树。


ConnectionHandler處理過(guò)程

public abstract class AbstractProtocol<S> implements ProtocolHandler,
        MBeanRegistration {

    protected static class ConnectionHandler<S> implements AbstractEndpoint.Handler<S> {

        private final AbstractProtocol<S> proto;
        private final RequestGroupInfo global = new RequestGroupInfo();
        private final AtomicLong registerCount = new AtomicLong(0);
        private final Map<S,Processor> connections = new ConcurrentHashMap<>();
        private final RecycledProcessors recycledProcessors = new RecycledProcessors(this);

        @Override
        public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
                // 省略相關(guān)代碼
                if (processor == null) {
                    processor = recycledProcessors.pop();
                }
                if (processor == null) {
                    processor = getProtocol().createProcessor();
                    register(processor);
                }

                do {
                    // 執(zhí)行Http11Processor的 process 方法
                    state = processor.process(wrapper, status);
                } while ( state == SocketState.UPGRADING);

                return state;
            } catch (Throwable e) {
            } 
        }
    }
}

public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> {
    @Override
    protected Processor createProcessor() {
        // 創(chuàng)建Http11Processor對(duì)象
        Http11Processor processor = new Http11Processor(getMaxHttpHeaderSize(),
                getAllowHostHeaderMismatch(), getRejectIllegalHeaderName(), getEndpoint(),
                getMaxTrailerSize(), allowedTrailerHeaders, getMaxExtensionSize(),
                getMaxSwallowSize(), httpUpgradeProtocols, getSendReasonPhrase());
        // 省略相關(guān)代碼
        return processor;
    }
}

public class Http11Processor extends AbstractProcessor {

    public Http11Processor(int maxHttpHeaderSize, boolean allowHostHeaderMismatch,
            boolean rejectIllegalHeaderName, AbstractEndpoint<?> endpoint, int maxTrailerSize,
            Set<String> allowedTrailerHeaders, int maxExtensionSize, int maxSwallowSize,
            Map<String,UpgradeProtocol> httpUpgradeProtocols, boolean sendReasonPhrase) {

        super(endpoint);
        // 省略相關(guān)代碼
    }
}

public abstract class AbstractProcessor extends AbstractProcessorLight implements ActionHook {
    protected Adapter adapter;
    protected final AsyncStateMachine asyncStateMachine;
    private volatile long asyncTimeout = -1;
    protected final AbstractEndpoint<?> endpoint;
    protected final Request request;
    protected final Response response;
    protected volatile SocketWrapperBase<?> socketWrapper = null;
    protected volatile SSLSupport sslSupport;
    private ErrorState errorState = ErrorState.NONE;

    public AbstractProcessor(AbstractEndpoint<?> endpoint) {
        this(endpoint, new Request(), new Response());
    }

    protected AbstractProcessor(AbstractEndpoint<?> endpoint, Request coyoteRequest,
            Response coyoteResponse) {
        this.endpoint = endpoint;
        asyncStateMachine = new AsyncStateMachine(this);
        request = coyoteRequest;
        response = coyoteResponse;
        response.setHook(this);
        request.setResponse(response);
        request.setHook(this);
    }
}
  • ConnectionHandler通過(guò)Http11NioProtocol的createProcessor方法創(chuàng)建 Processor對(duì)象。通過(guò)recycledProcessors實(shí)現(xiàn)processor的重用性。
  • Http11Processor作為processor 對(duì)象,內(nèi)部包含Request和Response對(duì)象嘲碧。
  • Http11Processor的process方法負(fù)責(zé)處理請(qǐng)求邏輯羡洁。
  • Http11Processor的重用意味著每次請(qǐng)來(lái)請(qǐng)求都要重置內(nèi)部Request和Response對(duì)象。


Http11Processor 處理過(guò)程

public abstract class AbstractProcessorLight implements Processor {

    private Set<DispatchType> dispatches = new CopyOnWriteArraySet<>();
    protected Adapter adapter;
    // Http11Processor內(nèi)部包含Request 和 Response對(duì)象
    protected final Request request;
    protected final Response response;

    @Override
    public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
            throws IOException {

        SocketState state = SocketState.CLOSED;
        Iterator<DispatchType> dispatches = null;
        do {
            if (dispatches != null) {
            } else if (status == SocketEvent.OPEN_READ){
                // 執(zhí)行對(duì)應(yīng)的邏輯
                state = service(socketWrapper);
            } 
            // 省略相關(guān)代碼
        } while (state == SocketState.ASYNC_END ||
                dispatches != null && state != SocketState.CLOSED);

        return state;
    }
}

public abstract class AbstractProcessor 
       extends AbstractProcessorLight implements ActionHook {

    protected Adapter adapter;
    private volatile long asyncTimeout = -1;
    protected final AbstractEndpoint<?> endpoint;
    protected final Request request;
    protected final Response response;
    protected volatile SocketWrapperBase<?> socketWrapper = null;
}

public class Http11Processor extends AbstractProcessor {

    @Override
    public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        // 省略相關(guān)代碼
        while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
                sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
            try {
                // 解析請(qǐng)求
                if (!inputBuffer.parseRequestLine(keptAlive)) {
                    if (inputBuffer.getParsingRequestLinePhase() == -1) {
                        return SocketState.UPGRADING;
                    } else if (handleIncompleteRequestLineRead()) {
                        break;
                    }
                }
            } catch (Throwable t) {
            }

            // 解析 Request 對(duì)象
            if (!getErrorState().isError()) {
                try {
                    prepareRequest();
                } catch (Throwable t) {
                }
            }

            if (!getErrorState().isError()) {
                try {
                    getAdapter().service(request, response);
                } catch (Throwable t) {
                }
            }

            sendfileState = processSendfile(socketWrapper);
        }
    }
}
  • Http11Processor對(duì)象能夠被重用,每次處理請(qǐng)求都會(huì)重新初始化Request對(duì)象。
  • Http11Processor處理每次請(qǐng)求通過(guò)inputBuffer.parseRequestLine和prepareRequest來(lái)重新初始化Request對(duì)象。
  • Http11Processor的 service 內(nèi)部調(diào)用CoyoteAdapter的service方法湿酸。


CoyoteAdapter 執(zhí)行流程

org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
      // 5、StandardWrapperValve
      at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
      // 4灭美、StandardContextValve
      at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
      at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
      // 3推溃、StandardHostValve
      at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
      at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
      // 2、StandardEngineValve
      at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
      // 1届腐、CoyoteAdapter
      at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
      at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
      at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
      at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
      at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
      at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
      - locked <0x19b6> (a org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
      at java.lang.Thread.run(Thread.java:748)
  • CoyoteAdapter的執(zhí)行流程按照 Tomcat 內(nèi)部對(duì)象的經(jīng)典順序進(jìn)行執(zhí)行铁坎,見(jiàn)調(diào)用棧注釋。
  • 整個(gè)執(zhí)行過(guò)程最終調(diào)用的是StandardWrapperValve的 invoke 方法犁苏。


Tomcat Filter職責(zé)鏈

final class StandardWrapperValve
    extends ValveBase {

    public StandardWrapperValve() {
        super(true);
    }

    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        Servlet servlet = null;

        try {
            if (!unavailable) {
                // wrapper是StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[].StandardWrapper
                // 創(chuàng)建一個(gè) servlet 對(duì)象
                servlet = wrapper.allocate();
            }
        } catch (Throwable e) {
        }

        // 創(chuàng)建過(guò)濾器職責(zé)鏈
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

        try {
            if ((servlet != null) && (filterChain != null)) {
                if (context.getSwallowOutput()) {
                    // 省略代碼
                } else {
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                        // 通過(guò)職責(zé)鏈開(kāi)始執(zhí)行
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }
            }
        } catch (Throwable e) {
        }

        // 釋放職責(zé)鏈硬萍,職責(zé)鏈的釋放表示所有的filter 設(shè)置為 null
        if (filterChain != null) {
            filterChain.release();
        }

        // 回收 servlet 對(duì)象
        try {
            if (servlet != null) {
                wrapper.deallocate(servlet);
            }
        } catch (Throwable e) {
        }
    }

    public HttpServletResponse getResponse() {
        if (facade == null) {
            facade = new ResponseFacade(this);
        }
        if (applicationResponse == null) {
            applicationResponse = facade;
        }
        return applicationResponse;
    }

    public HttpServletRequest getRequest() {
        if (facade == null) {
            facade = new RequestFacade(this);
        }
        if (applicationRequest == null) {
            applicationRequest = facade;
        }
        return applicationRequest;
    }
}
  • StandardWrapperValve負(fù)責(zé)創(chuàng)建經(jīng)典的 servlet 對(duì)象,通過(guò)wrapper.allocate創(chuàng)建围详,內(nèi)部實(shí)現(xiàn)了 servlet 的單例模式朴乖。
  • StandardWrapperValve負(fù)責(zé)創(chuàng)建 FilterChain 對(duì)象祖屏,通過(guò)createFilterChain方法。
  • filterChain.doFilter方法中的request.getRequest()和response.getResponse()負(fù)責(zé)將 request 對(duì)象轉(zhuǎn)換成RequestFacade對(duì)象买羞,將 response 對(duì)象轉(zhuǎn)換成ResponseFacade對(duì)象袁勺。


Tomcat FilterChain創(chuàng)建和釋放

public final class ApplicationFilterChain implements FilterChain {

    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    private int pos = 0;
    private int n = 0;
    public static final int INCREMENT = 10;
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    private Servlet servlet = null;
}

public final class ApplicationFilterFactory {
    public static ApplicationFilterChain createFilterChain(ServletRequest request,
            Wrapper wrapper, Servlet servlet) {

        ApplicationFilterChain filterChain = null;

        if (request instanceof Request) {
            Request req = (Request) request;
            if (Globals.IS_SECURITY_ENABLED) {
                filterChain = new ApplicationFilterChain();
            } else {
                filterChain = (ApplicationFilterChain) req.getFilterChain();
                if (filterChain == null) {
                    filterChain = new ApplicationFilterChain();
                    req.setFilterChain(filterChain);
                }
            }
        } else {
            filterChain = new ApplicationFilterChain();
        }

        // 設(shè)置職責(zé)鏈的filterChain內(nèi)部的 sevlet 對(duì)象
        filterChain.setServlet(servlet);
        filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

        StandardContext context = (StandardContext) wrapper.getParent();
        FilterMap filterMaps[] = context.findFilterMaps();

        if ((filterMaps == null) || (filterMaps.length == 0))
            return (filterChain);

        DispatcherType dispatcher =
                (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

        String requestPath = null;
        Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
        if (attribute != null){
            requestPath = attribute.toString();
        }

        String servletName = wrapper.getName();

        // Add the relevant path-mapped filters to this filter chain
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersURL(filterMaps[i], requestPath))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Add filters that match on servlet name second
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersServlet(filterMaps[i], servletName))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        return filterChain;
    }

    void addFilter(ApplicationFilterConfig filterConfig) {

        for(ApplicationFilterConfig filter:filters)
            if(filter==filterConfig)
                return;

        if (n == filters.length) {
            ApplicationFilterConfig[] newFilters =
                new ApplicationFilterConfig[n + INCREMENT];
            System.arraycopy(filters, 0, newFilters, 0, n);
            filters = newFilters;
        }
        filters[n++] = filterConfig;
    }


    void release() {
        for (int i = 0; i < n; i++) {
            filters[i] = null;
        }
        n = 0;
        pos = 0;
        servlet = null;
        servletSupportsAsync = false;
    }
}
  • FilterChain內(nèi)部包含ApplicationFilterConfig數(shù)組保存Filter 對(duì)象。
  • FilterChain每次請(qǐng)求開(kāi)始的時(shí)候進(jìn)行創(chuàng)建畜普,結(jié)束的時(shí)候負(fù)責(zé)回收(參考release方法)期丰。


Tomcat FilterChain的執(zhí)行

public final class ApplicationFilterChain implements FilterChain {

    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    private int pos = 0;
    private int n = 0;
    public static final int INCREMENT = 10;
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    private Servlet servlet = null;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {

        if( Globals.IS_SECURITY_ENABLED ) {
            // 省略相關(guān)代碼
        } else {
            internalDoFilter(request,response);
        }

    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {

        // 執(zhí)行職責(zé)鏈
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();
                if( Globals.IS_SECURITY_ENABLED ) {
                   // 省略代碼
                } else {
                    filter.doFilter(request, response, this);
                }
            } catch (Throwable e) {
            }
            return;
        }

        // 執(zhí)行 servlet 本身的服務(wù)
        try {
            if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse) &&
                    Globals.IS_SECURITY_ENABLED ) {
               // 省略相關(guān)代碼
            } else {
                // 執(zhí)行 serlvet 的服務(wù),默認(rèn)是DispatcherServlet對(duì)象
                servlet.service(request, response);
            }
        } catch (Throwable e) {
        } finally {
        }
    }
 }
  • 職責(zé)鏈的執(zhí)行有兩種視角吃挑,一種是以上帝視角外部調(diào)用 for 循環(huán)執(zhí)行钝荡,一種是每個(gè) Filter 自驅(qū)執(zhí)行并觸發(fā)下一個(gè) Filter,F(xiàn)ilterChain選擇的是后者儒鹿。
  • FilterChain的執(zhí)行內(nèi)部通過(guò) pos 和 n 的位置標(biāo)記判斷是否執(zhí)行結(jié)束化撕。
public class TimeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("time filter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("time filter start");
        long startTime = System.currentTimeMillis();
        // filter內(nèi)部需要調(diào)用filterChain繼續(xù)執(zhí)行下一個(gè)Filter
        filterChain.doFilter(servletRequest, servletResponse);

        long endTime = System.currentTimeMillis();
        System.out.println("time filter consume " + (endTime - startTime) + " ms");
        System.out.println("time filter end");
    }
}
  • Tomcat 的 Filter 是通過(guò) filter 對(duì)象內(nèi)部執(zhí)行filterChain.doFilter來(lái)驅(qū)動(dòng)下一個(gè)Filter對(duì)象的執(zhí)行。


Tomcat Servlet 的創(chuàng)建

public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {

    @Override
    public Servlet allocate() throws ServletException {
        boolean newInstance = false;

        // singleThreadModel = false
        if (!singleThreadModel) {
            // instance = DispatcherServlet
            if (instance == null || !instanceInitialized) {
                synchronized (this) {
                    if (instance == null) {
                        try {
                            instance = loadServlet();
                            newInstance = true;
                            if (!singleThreadModel) {
                                countAllocated.incrementAndGet();
                            }
                        } catch (ServletException e) {
                            throw e;
                        } catch (Throwable e) {
                        }
                    }
                    if (!instanceInitialized) {
                        initServlet(instance);
                    }
                }
            }

            if (singleThreadModel) {
                if (newInstance) {
                    synchronized (instancePool) {
                        instancePool.push(instance);
                        nInstances++;
                    }
                }
            } else {
                if (!newInstance) {
                    countAllocated.incrementAndGet();
                }
                // 最終返回的單例
                return instance;
            }
        }

        synchronized (instancePool) {
            while (countAllocated.get() >= nInstances) {
                if (nInstances < maxInstances) {
                    try {
                        instancePool.push(loadServlet());
                        nInstances++;
                    } catch (ServletException e) {
                    } catch (Throwable e) {
                    }
                } else {
                    try {
                        instancePool.wait();
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
            }
            countAllocated.incrementAndGet();
            return instancePool.pop();
        }
    }
}
  • Servlet屬于單例實(shí)例约炎。


Spring的DispatcherServlet

public abstract class HttpServlet extends GenericServlet {

    private static final long serialVersionUID = 1L;
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";
    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    private static final String LSTRING_FILE =
        "javax.servlet.http.LocalStrings";
    private static final ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);

    public HttpServlet() {
    }

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
    }

    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    }

    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    }

    protected void doDelete(HttpServletRequest req,
                            HttpServletResponse resp)
        throws ServletException, IOException {
    }


    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;  // RequestFacade
        HttpServletResponse response;  // ResponseFacade

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
    }
}


public abstract class HttpServlet extends GenericServlet {

    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
        } else {
        }
    }
}
  • DispatcherServlet內(nèi)部通過(guò) method 區(qū)分不同的邏輯執(zhí)行。
public class DispatcherServlet extends FrameworkServlet {

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        
        // 省略代碼
        try {
            this.doDispatch(request, response);
        } finally {
        }
    }

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            try {
                ModelAndView mv = null;
                Object dispatchException = null;

                try {
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    mappedHandler = this.getHandler(processedRequest);

                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    String method = request.getMethod();
                    // ha = RequestMappingHandlerAdapter蟹瘾,對(duì)應(yīng)的執(zhí)行對(duì)象
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }

                    this.applyDefaultViewName(processedRequest, mv);
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                } catch (Throwable var21) {
                }

                this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
            } catch (Exception var22) {
            } catch (Throwable var23) {
            }
        } finally {
        }
    }
}
  • DispatcherServlet的doDispatch通過(guò)對(duì)應(yīng)的mappedHandler執(zhí)行對(duì)應(yīng)的邏輯
public class InvocableHandlerMethod extends HandlerMethod {

    private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {

        MethodParameter[] parameters = getMethodParameters();
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            MethodParameter parameter = parameters[i];
            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
            args[i] = resolveProvidedArgument(parameter, providedArgs);
            if (args[i] != null) {
                continue;
            }
            if (this.argumentResolvers.supportsParameter(parameter)) {
                try {
                    args[i] = this.argumentResolvers.resolveArgument(
                            parameter, mavContainer, request, this.dataBinderFactory);
                    continue;
                }
                catch (Exception ex) {
                }
            }
        }
        return args;
    }
}

public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

    private final List<HandlerMethodArgumentResolver> argumentResolvers =
            new LinkedList<HandlerMethodArgumentResolver>();
    private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
            new ConcurrentHashMap<MethodParameter, HandlerMethodArgumentResolver>(256);


    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
        HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
        if (result == null) {
            for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
                if (methodArgumentResolver.supportsParameter(parameter)) {
                    result = methodArgumentResolver;
                    this.argumentResolverCache.put(parameter, result);
                    break;
                }
            }
        }
        return result;
    }
}
  • DispatcherServlet通過(guò)InvocableHandlerMethod類(lèi)實(shí)現(xiàn)不同協(xié)議對(duì)應(yīng)的請(qǐng)求參數(shù)的解析圾浅。


參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市憾朴,隨后出現(xiàn)的幾起案子狸捕,更是在濱河造成了極大的恐慌,老刑警劉巖众雷,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灸拍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡砾省,警方通過(guò)查閱死者的電腦和手機(jī)鸡岗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)编兄,“玉大人轩性,你說(shuō)我怎么就攤上這事『菰В” “怎么了揣苏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)件舵。 經(jīng)常有香客問(wèn)我卸察,道長(zhǎng),這世上最難降的妖魔是什么铅祸? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任坑质,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘洪乍。我一直安慰自己眯杏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布壳澳。 她就那樣靜靜地躺著岂贩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪巷波。 梳的紋絲不亂的頭發(fā)上萎津,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天,我揣著相機(jī)與錄音抹镊,去河邊找鬼锉屈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛垮耳,可吹牛的內(nèi)容都是我干的颈渊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼终佛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼俊嗽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起铃彰,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绍豁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后牙捉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體竹揍,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年邪铲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芬位。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡霜浴,死狀恐怖晶衷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阴孟,我是刑警寧澤晌纫,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站永丝,受9級(jí)特大地震影響锹漱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜慕嚷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一哥牍、第九天 我趴在偏房一處隱蔽的房頂上張望毕泌。 院中可真熱鬧,春花似錦嗅辣、人聲如沸撼泛。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)愿题。三九已至,卻和暖如春蛙奖,著一層夾襖步出監(jiān)牢的瞬間潘酗,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工雁仲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仔夺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓攒砖,卻偏偏與公主長(zhǎng)得像缸兔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子祭衩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容