Tomcat源码分析(三)Container容器

    通过前面几篇文章的分析,我们可以看出Tomcat的核心就是Container,Engine, Host, Context和Wrapper都是Container的子类,所有的请求都是围绕着四个类展开的,所以Container绝对是Tomcat的重中之重,本文就对Tomcat的Container进行分析。
 

  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处理。

    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处理。

    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方法处理请求。

    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;
    }
    

     

转载于:https://my.oschina.net/u/2950586/blog/808109

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值