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对象的传递。

  • 相关阅读:
    vijos 1066 弱弱的战壕 树状数组
    vijos 1057 盖房子 简单DP
    完全背包
    HDU 1203 和 HDU 2191
    dp 01背包,完全背包,多重背包 模板
    UVA11624 Fire!
    我们要学习的算法
    Find a way 两路广搜
    NYOJ 最小步数(简单深搜与广搜)
    HDU Dungeon Master广搜
  • 原文地址:https://www.cnblogs.com/grasp/p/10100126.html
Copyright © 2011-2022 走看看