Tomcat源碼分析(三)Container容器

    經過前面幾篇文章的分析,咱們能夠看出Tomcat的核心就是Container,Engine, Host, Context和Wrapper都是Container的子類,全部的請求都是圍繞着四個類展開的,因此Container絕對是Tomcat的重中之重,本文就對Tomcat的Container進行分析。
 java

  1. Container
    Container總體結構如圖所示:

    從圖中咱們能夠看出Engine, Host, Context, Wrapper都是Container的子類,StandardEngine,StandardHost, StandardContext, StandardWrapper都是經過繼承ContainerBase來實現父類的方法,因此它們都是Container,擁有Container的全部屬性。ContainerBase又組合了Container,ContainerBase均可以設置一個parent和多個children,從而實現了父子結構。

    Container是用於執行來自客戶端的請求並返回結果,Container中使用Pipeline管理一系列的Vavle,Valve是實際處理請求的實體,Valve處理的請求是有序的,從Pipeline的頭部依次執行。 Container的主要設計以下:
    public interface Container extends Lifecycle {
    
        /**
         * 返回Container的Pipeline,Pipeline上有多個Valve。
         * 當有請求時Container會調用Pipeline上的Valve處理。
         */
        public Pipeline getPipeline();
        
        /**
         * Container設計是父子關係的,每一個Container均可以有個Parent。
         * Engine沒有Parent, Host的Parent是Engine。
         */
        public Container getParent();
    
        public void setParent(Container container);
    
        public ClassLoader getParentClassLoader();
    
        public void setParentClassLoader(ClassLoader parent);
    
        /**
         * Container能夠有多個Child, Engine能夠有多個Host, Wrapper則沒有Child。
         */
        public void addChild(Container child);
    
        public void addContainerListener(ContainerListener listener);
    
        public void addPropertyChangeListener(PropertyChangeListener listener);
    
        public Container findChild(String name);
    
        public Container[] findChildren();
    
        public ContainerListener[] findContainerListeners();
    
        public void removeChild(Container child);
    
        public void removeContainerListener(ContainerListener listener);
    
        public void removePropertyChangeListener(PropertyChangeListener listener);
    
        public void fireContainerEvent(String type, Object data);
    
        /**
         * startTopThreads線程池設計用於啓動或者中止本身多個Child。
         * 並行的調用多個Child的start/stop方法。
         */
        public int getStartStopThreads();
    
        public void setStartStopThreads(int startStopThreads);
    }

    ContainerBase繼承了LifecycleBeanBase並實現了Container的全部屬性。ContainerBase主要設計以下:
    public abstract class ContainerBase extends LifecycleMBeanBase
            implements Container {
    
        // children記錄了Container的多個子Container
        protected final HashMap<String, Container> children = new HashMap<>();
    
        // parent記錄了Container所屬的父親Container
        protected Container parent = null;
    
        // pipeline記錄多個Vavle
        protected final Pipeline pipeline = new StandardPipeline(this);
    
        // startStopExecutor用於併發執行children的start和stop
        private int startStopThreads = 1;
        protected ThreadPoolExecutor startStopExecutor;
    
        // 後臺線程用於定時執行任務
        private Thread thread = null;
    
        @Override
        public Container getParent() {
            return (parent);
        }
    
        /**
         * 設置父Container,若是Contain拒絕設爲子容器會拋出異常,例如Engine
         */
        @Override
        public void setParent(Container container) {
    
            Container oldParent = this.parent;
            this.parent = container;
            support.firePropertyChange("parent", oldParent, this.parent);
    
        }
    
        @Override
        public Pipeline getPipeline() {
            return (this.pipeline);
        }
    
        @Override
        public void addChild(Container child) {
            if (Globals.IS_SECURITY_ENABLED) {
                PrivilegedAction<Void> dp =
                    new PrivilegedAddChild(child);
                AccessController.doPrivileged(dp);
            } else {
                addChildInternal(child);
            }
        }
    
        private void addChildInternal(Container child) {
    
            if( log.isDebugEnabled() )
                log.debug("Add child " + child + " " + this);
            synchronized(children) {
                if (children.get(child.getName()) != null)
                    throw new IllegalArgumentException("addChild:  Child name '" +
                                                       child.getName() +
                                                       "' is not unique");
                child.setParent(this);  // May throw IAE
                children.put(child.getName(), child);
            }
    
            // Start child
            // Don't do this inside sync block - start can be a slow process and
            // locking the children object can cause problems elsewhere
            try {
                if ((getState().isAvailable() ||
                        LifecycleState.STARTING_PREP.equals(getState())) &&
                        startChildren) {
                    child.start();
                }
            } catch (LifecycleException e) {
                log.error("ContainerBase.addChild: start: ", e);
                throw new IllegalStateException("ContainerBase.addChild: start: " + e);
            } finally {
                fireContainerEvent(ADD_CHILD_EVENT, child);
            }
        }
    
        @Override
        public Container findChild(String name) {
            if (name == null) {
                return null;
            }
            synchronized (children) {
                return children.get(name);
            }
        }
    
        @Override
        public Container[] findChildren() {
            synchronized (children) {
                Container results[] = new Container[children.size()];
                return children.values().toArray(results);
            }
        }
    
        @Override
        public void removeChild(Container child) {
    
            if (child == null) {
                return;
            }
    
            try {
                if (child.getState().isAvailable()) {
                    child.stop();
                }
            } catch (LifecycleException e) {
                log.error("ContainerBase.removeChild: stop: ", e);
            }
    
            try {
                // child.destroy() may have already been called which would have
                // triggered this call. If that is the case, no need to destroy the
                // child again.
                if (!LifecycleState.DESTROYING.equals(child.getState())) {
                    child.destroy();
                }
            } catch (LifecycleException e) {
                log.error("ContainerBase.removeChild: destroy: ", e);
            }
    
            synchronized(children) {
                if (children.get(child.getName()) == null)
                    return;
                children.remove(child.getName());
            }
    
            fireContainerEvent(REMOVE_CHILD_EVENT, child);
        }
    
        @Override
        protected void initInternal() throws LifecycleException {
            BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
            startStopExecutor = new ThreadPoolExecutor(
                    getStartStopThreadsInternal(),
                    getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
                    startStopQueue,
                    new StartStopThreadFactory(getName() + "-startStop-"));
            startStopExecutor.allowCoreThreadTimeOut(true);
            super.initInternal();
        }
    
        /**
         * Container啓動過程,經過線程池併發啓動全部Children
         */
        @Override
        protected synchronized void startInternal() throws LifecycleException {
    
            // Start our subordinate components, if any
            logger = null;
            getLogger();
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).start();
            }
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).start();
            }
    
            // Start our child containers, if any
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (int i = 0; i < children.length; i++) {
                results.add(startStopExecutor.submit(new StartChild(children[i])));
            }
    
            boolean fail = false;
            for (Future<Void> result : results) {
                try {
                    result.get();
                } catch (Exception e) {
                    log.error(sm.getString("containerBase.threadedStartFailed"), e);
                    fail = true;
                }
    
            }
            if (fail) {
                throw new LifecycleException(
                        sm.getString("containerBase.threadedStartFailed"));
            }
    
            // Start the Valves in our pipeline (including the basic), if any
            if (pipeline instanceof Lifecycle)
                ((Lifecycle) pipeline).start();
    
    
            setState(LifecycleState.STARTING);
    
            // Start our thread
            threadStart();
    
        }
    
        /**
         * Container中止過程,經過線程池併發中止全部Children
         */
        @Override
        protected synchronized void stopInternal() throws LifecycleException {
    
            // Stop our thread
            threadStop();
    
            setState(LifecycleState.STOPPING);
    
            // Stop the Valves in our pipeline (including the basic), if any
            if (pipeline instanceof Lifecycle &&
                    ((Lifecycle) pipeline).getState().isAvailable()) {
                ((Lifecycle) pipeline).stop();
            }
    
            // Stop our child containers, if any
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (int i = 0; i < children.length; i++) {
                results.add(startStopExecutor.submit(new StopChild(children[i])));
            }
    
            boolean fail = false;
            for (Future<Void> result : results) {
                try {
                    result.get();
                } catch (Exception e) {
                    log.error(sm.getString("containerBase.threadedStopFailed"), e);
                    fail = true;
                }
            }
            if (fail) {
                throw new LifecycleException(
                        sm.getString("containerBase.threadedStopFailed"));
            }
    
            // Stop our subordinate components, if any
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).stop();
            }
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).stop();
            }
        }
    
        @Override
        protected void destroyInternal() throws LifecycleException {
    
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).destroy();
            }
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).destroy();
            }
    
            // Stop the Valves in our pipeline (including the basic), if any
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).destroy();
            }
    
            // Remove children now this container is being destroyed
            for (Container child : findChildren()) {
                removeChild(child);
            }
    
            // Required if the child is destroyed directly.
            if (parent != null) {
                parent.removeChild(this);
            }
    
            // If init fails, this may be null
            if (startStopExecutor != null) {
                startStopExecutor.shutdownNow();
            }
    
            super.destroyInternal();
        }
    
        public synchronized void addValve(Valve valve) {
            pipeline.addValve(valve);
        }
    
        /**
         * 定時執行上下文後臺任務
         */
        @Override
        public void backgroundProcess() {
    
            if (!getState().isAvailable())
                return;
    
            Cluster cluster = getClusterInternal();
            if (cluster != null) {
                try {
                    cluster.backgroundProcess();
                } catch (Exception e) {
                    log.warn(sm.getString("containerBase.backgroundProcess.cluster",
                            cluster), e);
                }
            }
            Realm realm = getRealmInternal();
            if (realm != null) {
                try {
                    realm.backgroundProcess();
                } catch (Exception e) {
                    log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);
                }
            }
            Valve current = pipeline.getFirst();
            while (current != null) {
                try {
                    current.backgroundProcess();
                } catch (Exception e) {
                    log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);
                }
                current = current.getNext();
            }
            fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
        }
    
        /**
         * ContainerBackgroundProcessor繼承Runnable用於定時執行後臺任務
         */
        protected class ContainerBackgroundProcessor implements Runnable {
    
            @Override
            public void run() {
                Throwable t = null;
                String unexpectedDeathMessage = sm.getString(
                        "containerBase.backgroundProcess.unexpectedThreadDeath",
                        Thread.currentThread().getName());
                try {
                    while (!threadDone) {
                        try {
                            Thread.sleep(backgroundProcessorDelay * 1000L);
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                        if (!threadDone) {
                            processChildren(ContainerBase.this);
                        }
                    }
                } catch (RuntimeException|Error e) {
                    t = e;
                    throw e;
                } finally {
                    if (!threadDone) {
                        log.error(unexpectedDeathMessage, t);
                    }
                }
            }
    
            protected void processChildren(Container container) {
                ClassLoader originalClassLoader = null;
    
                try {
                    if (container instanceof Context) {
                        Loader loader = ((Context) container).getLoader();
                        // Loader will be null for FailedContext instances
                        if (loader == null) {
                            return;
                        }
    
                        // Ensure background processing for Contexts and Wrappers
                        // is performed under the web app's class loader
                        originalClassLoader = ((Context) container).bind(false, null);
                    }
                    container.backgroundProcess();
                    Container[] children = container.findChildren();
                    for (int i = 0; i < children.length; i++) {
                        if (children[i].getBackgroundProcessorDelay() <= 0) {
                            processChildren(children[i]);
                        }
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error("Exception invoking periodic operation: ", t);
                } finally {
                    if (container instanceof Context) {
                        ((Context) container).unbind(false, originalClassLoader);
                   }
                }
            }
        }
    
        /**
         * StartChild實現Callable,加入Executor實現異步啓動Child
         */
        private static class StartChild implements Callable<Void> {
    
            private Container child;
    
            public StartChild(Container child) {
                this.child = child;
            }
    
            @Override
            public Void call() throws LifecycleException {
                child.start();
                return null;
            }
        }
    
        /**
         * StopChild實現Callable,加入Executor實現異步中止Child
         */
        private static class StopChild implements Callable<Void> {
    
            private Container child;
    
            public StopChild(Container child) {
                this.child = child;
            }
    
            @Override
            public Void call() throws LifecycleException {
                if (child.getState().isAvailable()) {
                    child.stop();
                }
                return null;
            }
        }
    
        private static class StartStopThreadFactory implements ThreadFactory {
            private final ThreadGroup group;
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix;
    
            public StartStopThreadFactory(String namePrefix) {
                SecurityManager s = System.getSecurityManager();
                group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
                this.namePrefix = namePrefix;
            }
    
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());
                thread.setDaemon(true);
                return thread;
            }
        }
    }
    ContainerBase實現了大部分方法,Engine, Host, Context, Wrapper經過繼承ContainerBase就能夠實現Container接口。
     
  2. Engine
    Engine是完整的容器,Engine也是Container子類,Engine的擁有多個子Container,它們是多個虛擬主機,Engine的責任就是將Connector請求分配給虛擬機處理。它的標準實現類是StandardEngine,這個類沒有父容器了,若是調用setParent方法時將會報錯。StandardEngine結構如圖所示:

    StandardEngine繼承了ContainerBase因此StandardEngine擁有ContainerBase全部屬性,由於Container已是頂層容器,因此設置parent會拋出異常。
    public void setParent(Container container) {
        throw new IllegalArgumentException(sm.getString("standardEngine.notParent"));
    }

    StandardEngine經過建立StandardEngineValve,並將其加入本身的Pipeline中,經過StandardEngineValve來處理請求。
    public StandardEngine() {
    
        super();
        pipeline.setBasic(new StandardEngineValve())   
        /* Set the jmvRoute using the system property jvmRoute */
        try {
            setJvmRoute(System.getProperty("jvmRoute"));
        } catch(Exception ex) {
            log.warn(sm.getString("standardEngine.jvmRouteFail"));
        }
        // By default, the engine will hold the reloading thread
        backgroundProcessorDelay = 10;
    }

    StandardEngine經過Pipeline上的Vavle處理請求,StandardEngineVavle經過獲取Request的Host,將請求分發給Host的Pipeline上的Vavle處理。
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    
        // Select the Host to be used for this Request
        Host host = request.getHost();
        if (host == null) {
            response.sendError
                (HttpServletResponse.SC_BAD_REQUEST,
                 sm.getString("standardEngine.noHost",
                              request.getServerName()));
            return;
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(host.getPipeline().isAsyncSupported());
        }
    
        // Ask this Host to process this request
        host.getPipeline().getFirst().invoke(request, response);
    
    }

     
  3. Host
    Host是Engine的子容器,一個Host在Engine中表明一個虛擬主機,一個Host都會綁定一個域名,這個虛擬主機的做用就是運行多個應用,它負責安裝和展開這些應用,而且標識這個應用以便可以區分它們。它的子容器一般是Context,它除了關聯子容器外,還有就是保存一個主機應該有的信息,若是一個Engine下有多個Host對應多個域名,能夠經過設置Host的name實現。StandardHost結構如圖所示:

    StandardHost繼承了ContainerBase因此StandardHost也擁有ContainerBase全部屬性,和StandardEngine不一樣StandardHost既有父Container也有子Container。

    StandardHost一樣是經過Pipeline上的Vavle處理請求,StandardHostVavle經過獲取Request的Context,將請求分發給Context的Pipeline上的Vavle處理。web

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    	
        // Select the Context to be used for this Request
        Context context = request.getContext();
        if (context == null) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                 sm.getString("standardHost.noContext"));
            return;
        }
    	
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(context.getPipeline().isAsyncSupported());
        }
    	
        boolean asyncAtStart = request.isAsync();
        boolean asyncDispatching = request.isAsyncDispatching();
    	
        try {
            context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
    
            if (!asyncAtStart && !context.fireRequestInitEvent(request)) {
                // Don't fire listeners during async processing (the listener
                // fired for the request that called startAsync()).
                // If a request init listener throws an exception, the request
                // is aborted.
                return;
            }
    	
            // Ask this Context to process this request. Requests that are in
            // async mode and are not being dispatched to this resource must be
            // in error and have been routed here to check for application
            // defined error pages.
            try {
                if (!asyncAtStart || asyncDispatching) {
                    // context處理請求
                    context.getPipeline().getFirst().invoke(request, response);
                } else {
                    // Make sure this request/response is here because an error
                    // report is required.
                    if (!response.isErrorReportRequired()) {
                        throw new IllegalStateException(sm.getString("standardHost.asyncStateError"));
                    }
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                container.getLogger().error("Exception Processing " + request.getRequestURI(), t);
                // If a new error occurred while trying to report a previous
                // error allow the original error to be reported.
                if (!response.isErrorReportRequired()) {
                    request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
                    throwable(request, response, t);
                }
            }
    	
            // Now that the request/response pair is back under container
            // control lift the suspension so that the error handling can
            // complete and/or the container can flush any remaining data
            response.setSuspended(false);
    	
            Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
    	
            // Protect against NPEs if the context was destroyed during a
            // long running request.
            if (!context.getState().isAvailable()) {
                return;
            }
    	
            // Look for (and render if found) an application level error page
            if (response.isErrorReportRequired()) {
                if (t != null) {
                    throwable(request, response, t);
                } else {
                    status(request, response);
                }
            }
    	
            if (!request.isAsync() && (!asyncAtStart || !response.isErrorReportRequired())) {
                context.fireRequestDestroyEvent(request);
            }
        } finally {
            // Access a session (if present) to update last accessed time, based
            // on a strict interpretation of the specification
            if (ACCESS_SESSION) {
                request.getSession(false);
            }
    	
            context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
        }
    }

     

  4. Context
    Context定義在父容器Host中,Host不是必須的,可是要運行war程序,就必需要Host,由於war中必有web.xml文件,這個文件的解析就須要Host了,若是要有多個Host就要定義一個 top容器Engine了。StandardContext結構如圖所示:

    StandardContext繼承了ContainerBase因此StandardContext也擁有ContainerBase全部屬性,和StandardHost十分類似。


    StandardContext一樣是經過Pipeline上的Vavle處理請求,StandardContextVavle經過獲取Request的Context,將請求分發給Wrapper的Pipeline上的Vavle處理。session

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    	
        // Disallow any direct access to resources under WEB-INF or META-INF
        MessageBytes requestPathMB = request.getRequestPathMB();
        if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
                || (requestPathMB.equalsIgnoreCase("/META-INF"))
                || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
                || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
    	
        // Select the Wrapper to be used for this Request
        Wrapper wrapper = request.getWrapper();
        if (wrapper == null || wrapper.isUnavailable()) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
    	
        // Acknowledge the request
        try {
            response.sendAcknowledgement();
        } catch (IOException ioe) {
            container.getLogger().error(sm.getString(
                    "standardContextValve.acknowledgeException"), ioe);
            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
    
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
        }
        // wrapper處理請求
        wrapper.getPipeline().getFirst().invoke(request, response);
    }

     

  5. Wrapper
    Wrapper表明一個Servlet,它負責管理一個Servlet,包括的Servlet的裝載、初始化、執行以及資源回收。Wrapper是最底層的容器,它沒有子容器了,因此調用它的addChild將會報錯。StandardWrapper結構如圖所示:

    StandardWrapper繼承了ContainerBase因此StandardWrapper也擁有ContainerBase全部屬性,由於StandardWrapper已是底層容器,因此設置child會拋出異常。併發

    public void addChild(Container child) {
        throw new IllegalStateException(sm.getString("standardWrapper.notChild"));
    }


    StandardWrapper一樣是經過Pipeline上的Vavle處理請求,StandardContexttVavle最終將請求分發給ApplicationChainFilter處理,ApplicationChainFilter最終調用Servlet的service方法處理請求。app

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    	
        // Initialize local variables we may need
        boolean unavailable = false;
        Throwable throwable = null;
        // This should be a Request attribute...
        long t1=System.currentTimeMillis();
        requestCount.incrementAndGet();
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
        Context context = (Context) wrapper.getParent();
    	
        // Check for the application being marked unavailable
        if (!context.getState().isAvailable()) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                           sm.getString("standardContext.isUnavailable"));
            unavailable = true;
        }
    	
        // Check for the servlet being marked unavailable
        if (!unavailable && wrapper.isUnavailable()) {
            container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
                    wrapper.getName()));
            long available = wrapper.getAvailable();
            if ((available > 0L) && (available < Long.MAX_VALUE)) {
                response.setDateHeader("Retry-After", available);
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                        sm.getString("standardWrapper.isUnavailable",
                                wrapper.getName()));
            } else if (available == Long.MAX_VALUE) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                        sm.getString("standardWrapper.notFound",
                                wrapper.getName()));
            }
            unavailable = true;
        }
    	
        // Allocate a servlet instance to process this request
        try {
            if (!unavailable) {
                servlet = wrapper.allocate();
            }
        } catch (UnavailableException e) {
            container.getLogger().error(
                    sm.getString("standardWrapper.allocateException",
                            wrapper.getName()), e);
            long available = wrapper.getAvailable();
            if ((available > 0L) && (available < Long.MAX_VALUE)) {
                response.setDateHeader("Retry-After", available);
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                           sm.getString("standardWrapper.isUnavailable",
                                        wrapper.getName()));
            } else if (available == Long.MAX_VALUE) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                           sm.getString("standardWrapper.notFound",
                                        wrapper.getName()));
            }
        } catch (ServletException e) {
            container.getLogger().error(sm.getString("standardWrapper.allocateException",
                             wrapper.getName()), StandardWrapper.getRootCause(e));
            throwable = e;
            exception(request, response, e);
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.allocateException",
                             wrapper.getName()), e);
            throwable = e;
            exception(request, response, e);
            servlet = null;
        }
    	
        MessageBytes requestPathMB = request.getRequestPathMB();
        DispatcherType dispatcherType = DispatcherType.REQUEST;
        if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,requestPathMB);
        // Create the filter chain for this request
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    	
        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        try {
            if ((servlet != null) && (filterChain != null)) {
                // Swallow output if needed
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else {
                            filterChain.doFilter(request.getRequest(),
                                    response.getResponse());
                        }
                    } finally {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            context.getLogger().info(log);
                        }
                    }
                } else {
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                             // filterChain處理請求
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }
    	
            }
        } catch (ClientAbortException e) {
            throwable = e;
            exception(request, response, e);
        } catch (IOException e) {
            container.getLogger().error(sm.getString(
                    "standardWrapper.serviceException", wrapper.getName(),
                    context.getName()), e);
            throwable = e;
            exception(request, response, e);
        } catch (UnavailableException e) {
            container.getLogger().error(sm.getString(
                    "standardWrapper.serviceException", wrapper.getName(),
                    context.getName()), e);
            //            throwable = e;
           //            exception(request, response, e);
            wrapper.unavailable(e);
            long available = wrapper.getAvailable();
            if ((available > 0L) && (available < Long.MAX_VALUE)) {
                response.setDateHeader("Retry-After", available);
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                           sm.getString("standardWrapper.isUnavailable",
                                        wrapper.getName()));
            } else if (available == Long.MAX_VALUE) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND,
                            sm.getString("standardWrapper.notFound",
                                        wrapper.getName()));
            }
            // Do not save exception in 'throwable', because we
            // do not want to do exception(request, response, e) processing
        } catch (ServletException e) {
            Throwable rootCause = StandardWrapper.getRootCause(e);
            if (!(rootCause instanceof ClientAbortException)) {
                container.getLogger().error(sm.getString(
                        "standardWrapper.serviceExceptionRoot",
                        wrapper.getName(), context.getName(), e.getMessage()),
                        rootCause);
            }
            throwable = e;
            exception(request, response, e);
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString(
                    "standardWrapper.serviceException", wrapper.getName(),
                    context.getName()), e);
            throwable = e;
            exception(request, response, e);
        }
    	
        // Release the filter chain (if any) for this request
        if (filterChain != null) {
            filterChain.release();
        }
    	
        // Deallocate the allocated servlet instance
        try {
            if (servlet != null) {
                wrapper.deallocate(servlet);
            }
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.deallocateException",
                             wrapper.getName()), e);
            if (throwable == null) {
                throwable = e;
                exception(request, response, e);
            }
        }
    	
        // If this servlet has been marked permanently unavailable,
        // unload it and release this instance
        try {
            if ((servlet != null) &&
                (wrapper.getAvailable() == Long.MAX_VALUE)) {
                wrapper.unload();
            }
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.unloadException",
                             wrapper.getName()), e);
            if (throwable == null) {
                throwable = e;
                exception(request, response, e);
            }
        }
        long t2=System.currentTimeMillis();
    	
        long time=t2-t1;
        processingTime += time;
        if( time > maxTime) maxTime=time;
        if( time < minTime) minTime=time;
    }
相關文章
相關標籤/搜索