Tomcat源码分析(三)Container容器

编程入门 行业动态 更新时间:2024-10-10 15:20:52

Tomcat源码分析(三)Container<a href=https://www.elefans.com/category/jswz/34/1771431.html style=容器"/>

Tomcat源码分析(三)Container容器

2019独角兽企业重金招聘Python工程师标准>>>

    通过前面几篇文章的分析,我们可以看出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 LifecycleMBeanBaseimplements Container {// children记录了Container的多个子Containerprotected final HashMap<String, Container> children = new HashMap<>();// parent记录了Container所属的父亲Containerprotected Container parent = null;// pipeline记录多个Vavleprotected final Pipeline pipeline = new StandardPipeline(this);// startStopExecutor用于并发执行children的start和stopprivate int startStopThreads = 1;protected ThreadPoolExecutor startStopExecutor;// 后台线程用于定时执行任务private Thread thread = null;@Overridepublic Container getParent() {return (parent);}/*** 设置父Container,如果Contain拒绝设为子容器会抛出异常,例如Engine*/@Overridepublic void setParent(Container container) {Container oldParent = this.parent;this.parent = container;support.firePropertyChange("parent", oldParent, this.parent);}@Overridepublic Pipeline getPipeline() {return (this.pipeline);}@Overridepublic 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 IAEchildren.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 elsewheretry {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);}}@Overridepublic Container findChild(String name) {if (name == null) {return null;}synchronized (children) {return children.get(name);}}@Overridepublic Container[] findChildren() {synchronized (children) {Container results[] = new Container[children.size()];return children.values().toArray(results);}}@Overridepublic 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);}@Overrideprotected 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*/@Overrideprotected synchronized void startInternal() throws LifecycleException {// Start our subordinate components, if anylogger = 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 anyContainer 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 anyif (pipeline instanceof Lifecycle)((Lifecycle) pipeline).start();setState(LifecycleState.STARTING);// Start our threadthreadStart();}/*** Container停止过程,通过线程池并发停止所有Children*/@Overrideprotected synchronized void stopInternal() throws LifecycleException {// Stop our threadthreadStop();setState(LifecycleState.STOPPING);// Stop the Valves in our pipeline (including the basic), if anyif (pipeline instanceof Lifecycle &&((Lifecycle) pipeline).getState().isAvailable()) {((Lifecycle) pipeline).stop();}// Stop our child containers, if anyContainer 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 anyRealm realm = getRealmInternal();if (realm instanceof Lifecycle) {((Lifecycle) realm).stop();}Cluster cluster = getClusterInternal();if (cluster instanceof Lifecycle) {((Lifecycle) cluster).stop();}}@Overrideprotected 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 anyif (pipeline instanceof Lifecycle) {((Lifecycle) pipeline).destroy();}// Remove children now this container is being destroyedfor (Container child : findChildren()) {removeChild(child);}// Required if the child is destroyed directly.if (parent != null) {parent.removeChild(this);}// If init fails, this may be nullif (startStopExecutor != null) {startStopExecutor.shutdownNow();}super.destroyInternal();}public synchronized void addValve(Valve valve) {pipeline.addValve(valve);}/*** 定时执行上下文后台任务*/@Overridepublic 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 {@Overridepublic 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 instancesif (loader == null) {return;}// Ensure background processing for Contexts and Wrappers// is performed under the web app's class loaderoriginalClassLoader = ((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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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 threadbackgroundProcessorDelay = 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 RequestHost 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 requesthost.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 RequestContext 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 dataresponse.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 pageif (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 specificationif (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-INFMessageBytes 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 RequestWrapper wrapper = request.getWrapper();if (wrapper == null || wrapper.isUnavailable()) {response.sendError(HttpServletResponse.SC_NOT_FOUND);return;}// Acknowledge the requesttry {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 needboolean 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 unavailableif (!context.getState().isAvailable()) {response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,sm.getString("standardContext.isUnavailable"));unavailable = true;}// Check for the servlet being marked unavailableif (!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 requesttry {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 requestApplicationFilterChain filterChain =ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);// Call the filter chain for this request// NOTE: This also calls the servlet's service() methodtry {if ((servlet != null) && (filterChain != null)) {// Swallow output if neededif (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 requestif (filterChain != null) {filterChain.release();}// Deallocate the allocated servlet instancetry {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 instancetry {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;
    }
    

     

转载于:

更多推荐

Tomcat源码分析(三)Container容器

本文发布于:2024-02-11 11:37:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1680777.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:容器   源码   Tomcat   Container

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!