zoukankan      html  css  js  c++  java
  • tomcat源码 Container

    1.Container的有四个子容器,分别是Engine,Host,Context,Wrapper,如下:

    1、Engine:整个Catalina servlet引擎,标准实现为StandardEngine。
    2、Host:表示包含一个或多个Context容器的虚拟主机,标准实现为StandardHost。
    3、Context:表示一个web应用程序,对应着平时开发对应的一套程序,或者一个WEB-INF目录以及下面的web.xml文件一个Context可以有多个Wrapper,标准实现为StandardContext。
    4、Wrapper:包装一个独立的Servlet容器,每个Wrapper封装一个Servlet,标准实现为StandardWrapper。

    2.Container一个也有四个子接口Engine,Host,Context,Wrapper和一个默认实现类ContainerBase,另外这四个子容器都是对应一个StandardXXX实现类,都继承ContainerBase,并且Container还继承LifeCycle接口,所以这四个容器也是符合Tomcat的生命周期模式,结构图如下:

    每个Container容器都有对应的阀Valve,多个Valve组成了Pipeline,这就是Container的具体实现过程,也可以在server.xml文件中配置Pipeline和Valve的集合实现。管道Pipe包含了容器中要执行的任务,而每一个阀Valve表示一个具体的任务,在每个管道中,都会有一个默认的阀,可以添加任意数量的阀,可通过server.xml文件配置。对过滤器熟悉的话就会发现,管道和阀的工作机制和过滤器工作机制相似,Pipeline相当于过滤器链FilterChain,Valve相当于每一个过滤器Filter。阀可以处理传给它的request对象和response对象,处理完一个Valve后接着处理下一个Valve,最后处理的阀是基础阀。下面就追踪每一个容器的管道,解析容器处理请求的流程。

    首先是Engine容器,默认实现是StandardEngine,创建StandardEngine时实例化其基础阀,代码如下:

    public StandardEngine() {
    
        super();
        //设置基础阀StandardEngineValve
        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;
    
    }

    继续跟踪StandardEngineValve的invoke()方法,源码为:

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    
        // Select the Host to be used for this Request
        // 选出和该request相关的Host,在MappingData中保存了请求和容器(Host,Context,Wrapper)之间的映射
        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()得到Host对应的管道Pipeline,将request和response对象交给Host的阀去处理
        host.getPipeline().getFirst().invoke(request, response);
    
    }

    StandardEngineValve的invoke()方法是在CoyoteAdapter类中service方法中调用的,也就是Connector将请求交给Container的过程:

    public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
                throws Exception {
    
            Request request = (Request) req.getNote(ADAPTER_NOTES);
            Response response = (Response) res.getNote(ADAPTER_NOTES);
    
            ......
            
                // Parse and set Catalina and configuration specific
                // request parameters
                //根据request得到对应的MappingData,里面保存了解析地址对应的Engine,Host,Context,Wrapper,在后面的管道中使用
                postParseSuccess = postParseRequest(req, request, res, response);
                if (postParseSuccess) {
                    //check valves if we support async
                    request.setAsyncSupported(
                            connector.getService().getContainer().getPipeline().isAsyncSupported());
                    // Calling the container
                    //得到Connector关联的Container,然后将request和response对象交给Engine的管道Pineline中的阀去处理。
                    connector.getService().getContainer().getPipeline().getFirst().invoke(
                            request, response);
                }
                
            ......
        }

    这个service方法就是SocketProcessor#doRun--->Http11Processor#service--->CoyoteAdapter#service

    同样Host容器构造器中设置了其基础阀StandardHostValve:

    public StandardHost() {
    
        super();
        pipeline.setBasic(new StandardHostValve());
    
    }

    同样跟踪StandardHostValve的invoke方法:

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    
        // Select the Context to be used for this Request
        // 该request容器关联的Context,保存在MappingData中
        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 {
            //设置StandardHostValve的类加载器
            context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
    
            if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
                // 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 {
                // 将request传递给Context的阀去处理,有错误的页面必须在此处处理,不会继续向下传递到Context容器中
                if (!asyncAtStart || asyncDispatching) {
                    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) {
                context.fireRequestDestroyEvent(request.getRequest());
            }
        } 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);
        }
    }

    Context和Wrapper的管道和阀的实现过程与Engine和Host完全一样,不再继续分析。最后主要解析StandardWrapperValve的invoke()方法,看该方法如何将request交个一个servlet处理。鉴于该方法源码太长,只展示出了部分重要代码。

    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    
        ......
        //获取关联的StandardWrapper
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
        //wrapper的父容器Context
        Context context = (Context) wrapper.getParent();
    
        ......
    
        // Allocate a servlet instance to process this request
        // 分配一个servlet实例处理该request
        try {
            if (!unavailable) {
                //servlet可用时,分配servlet,接下来会跟踪allocate()方法
                servlet = wrapper.allocate();
            }
        } catch (UnavailableException e) {
            //分别设置了503错误和404 not found
            ......
        } catch (ServletException e) {
            ......
        } catch (Throwable e) {
            ......
        }
    
        ......
        // Create the filter chain for this request
        // 为该request设置过滤器
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
    
        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        // 过滤器作用于该request,并且此过程中调用了servlet的service()方法
        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.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }
    
            }
        } catch (ClientAbortException e) {
            ......
        } catch (IOException e) {
            ......
        } catch (UnavailableException e) {
            ......
        } catch (ServletException e) {
            ......
        } catch (Throwable e) {
            ......
        }
    
        // Release the filter chain (if any) for this request
        // 释放该request的过滤链
        if (filterChain != null) {
            filterChain.release();
        }
    
        // Deallocate the allocated servlet instance
        try {
            // 回收servlet容器实例
            if (servlet != null) {
                wrapper.deallocate(servlet);
            }
        } catch (Throwable e) {
            ......
        }
    
        ......
    }

    接着跟踪Wrapper的allocate源码:该方法主要功能是分配一个初始化了的servlet实例,其service方法可以被调用。

    public Servlet allocate() throws ServletException {
    
        // If we are currently unloading this servlet, throw an exception
        // servlet类没有加载时剖出异常
        if (unloading) {
            throw new ServletException(sm.getString("standardWrapper.unloading", getName()));
        }
    
        boolean newInstance = false;
    
        // If not SingleThreadedModel, return the same instance every time
        if (!singleThreadModel) {
            // Load and initialize our instance if necessary
            // servlet没有加载时要先载入该servlet
            if (instance == null || !instanceInitialized) {
                synchronized (this) {
                    if (instance == null) {
                        try {
                            if (log.isDebugEnabled()) {
                                log.debug("Allocating non-STM instance");
                            }
    
                            // Note: We don't know if the Servlet implements
                            // SingleThreadModel until we have loaded it.
                            //加载servlet,接下来继续分析loadServlet()方法
                            instance = loadServlet();
                            newInstance = true;
                            //类加载之前并不知道该servlet是否为singleThreadModel,在loadServlet()中会改变singleThreadModel的值,所以此处要再判断一次
                            if (!singleThreadModel) {
                                // For non-STM, increment here to prevent a race
                                // condition with unload. Bug 43683, test case
                                // #3
                                countAllocated.incrementAndGet();
                            }
                        } catch (ServletException e) {
                            throw e;
                        } catch (Throwable e) {
                            ExceptionUtils.handleThrowable(e);
                            throw new ServletException(sm.getString("standardWrapper.allocate"), e);
                        }
                    }
                    if (!instanceInitialized) {
                        //初始化servlet
                        initServlet(instance);
                    }
                }
            }
    
            //新加载的servlet实现singleThreadModel时将instance加入到instancePool中,否则直接返回instance
            if (singleThreadModel) {
                if (newInstance) {
                    // Have to do this outside of the sync above to prevent a
                    // possible deadlock
                    synchronized (instancePool) {
                        instancePool.push(instance);
                        nInstances++;
                    }
                }
            } else {
                if (log.isTraceEnabled()) {
                    log.trace("  Returning non-STM instance");
                }
                // For new instances, count will have been incremented at the
                // time of creation
                if (!newInstance) {
                    countAllocated.incrementAndGet();
                }
                return instance;
            }
        }
    
        //SingleThreadedModel类型的servlet时返回instancePool中的一个instance。
        synchronized (instancePool) {
            while (countAllocated.get() >= nInstances) {
                // Allocate a new instance if possible, or else wait
                if (nInstances < maxInstances) {
                    try {
                        instancePool.push(loadServlet());
                        nInstances++;
                    } catch (ServletException e) {
                        throw e;
                    } catch (Throwable e) {
                        ExceptionUtils.handleThrowable(e);
                        throw new ServletException(sm.getString("standardWrapper.allocate"), e);
                    }
                } else {
                    try {
                        instancePool.wait();
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
            }
            if (log.isTraceEnabled()) {
                log.trace("  Returning allocated STM instance");
            }
            countAllocated.incrementAndGet();
            return instancePool.pop();
        }
    }

    接下来看一下servlet的load过程loadServlet:

    public synchronized Servlet loadServlet() throws ServletException {
    
        // Nothing to do if we already have an instance or an instance pool
        // 如果不是SingleThreadModel类型的servlet,并且已经存在一个instance实例时,不需要加载。
        if (!singleThreadModel && (instance != null))
            return instance;
    
        ......
    
        Servlet servlet;
        try {
            long t1=System.currentTimeMillis();
            // Complain if no servlet class has been specified
            if (servletClass == null) {
                unavailable(null);
                throw new ServletException
                    (sm.getString("standardWrapper.notClass", getName()));
            }
    
            //Context容器中的instanceManager,是一个类加载器,其newInstance方法根据class路径加载servlet
            InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
            try {
                servlet = (Servlet) instanceManager.newInstance(servletClass);
            } catch (ClassCastException e) {
                unavailable(null);
                // Restore the context ClassLoader
                throw new ServletException
                    (sm.getString("standardWrapper.notServlet", servletClass), e);
            } catch (Throwable e) {
                ......
            }
    
            ......
    
            if (servlet instanceof SingleThreadModel) {
                if (instancePool == null) {
                    instancePool = new Stack<>();
                }
                //此处修改了singleThreadModel值,所以allocate方法中新加载servlet类后要重新判断这个值
                singleThreadModel = true;
            }
    
            //初始化刚加载的servlet
            initServlet(servlet);
    
            fireContainerEvent("load", this);
    
            loadTime=System.currentTimeMillis() -t1;
        } finally {
            if (swallowOutput) {
                String log = SystemLogHandler.stopCapture();
                if (log != null && log.length() > 0) {
                    if (getServletContext() != null) {
                        getServletContext().log(log);
                    } else {
                        out.println(log);
                    }
                }
            }
        }
        return servlet;
    
    }

    通过以上分析,我们知道了一个request请求是如何从Engine容器一路流动到了具体处理容器Wrapper中的,就是通过管道和阀的工作机制实现的,每一个容器都会对应一个管道,可以向管道中添加任意数量的阀valve,但必须要有一个基础阀,上一层的容器通过调用下一次容器的管道的阀的invoke方法实现request对象的传递。

  • 相关阅读:
    POJ 1703 Find them, Catch them
    POJ 2236 Wireless Network
    POJ 2010 Moo University
    POJ 2184 Cow Exhibition
    POJ 3280 Cheapest Palindrome
    POJ 3009 Curling 2.0
    POJ 3669 Meteor Shower
    POJ 2718 Smallest Difference
    POJ 3187 Backward Digit Sums
    POJ 3050 Hopscotch
  • 原文地址:https://www.cnblogs.com/grasp/p/10100126.html
Copyright © 2011-2022 走看看