Tomcat源码分析【十四】请求处理过程分析之Container

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

文章首发于:clawhub.club


经过Acceptor、Poller、SocketProcessor的合作处理,组装好了Request和Response,交由Container处理,Container处理逻辑也在工作线程中实行。
本篇文章从下面一段代码开始,位于CoyoteAdapter的service方法中:

    // Calling the container
    connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

通过debug,发现顺序走入了如下Valve(阀门、关卡):

    StandardEngineValve

    AbstractAccessLogValve
    ErrorReportValve
    StandardHostValve

    AuthenticatorBase
    StandardContextValve

    StandardWrapperValve

下面看核心的四个basic valve:

StandardEngineValve

     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) {
                // HTTP 0.9 or HTTP 1.0 request without a host when no default host
                // is defined. This is handled by the CoyoteAdapter.
                return;
            }
            if (request.isAsyncSupported()) {
                request.setAsyncSupported(host.getPipeline().isAsyncSupported());
            }
            // Ask this Host to process this request
            host.getPipeline().getFirst().invoke(request, response);
        }

直接调用Host中的Valve。

StandardHostValve

     @Override
        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) {
                return;
            }
            if (request.isAsyncSupported()) {
                request.setAsyncSupported(context.getPipeline().isAsyncSupported());
            }
            boolean asyncAtStart = request.isAsync();
            try {
                //将当前线程上下文类加载器更改为web应用程序类加载器。
                //如果没有定义web应用程序类加载器,或者当前线程已经在使用web应用程序类加载器,则不会进行任何更改。
                //如果类加载器被更改,并且有一个{@link org.apache.catalina.ThreadBindingListener}被配置,则调用
                //{@link org.apache.catalina.ThreadBindingListener#bind()}
                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
                // already in error must have been routed here to check for
                // application defined error pages so DO NOT forward them to the the
                // application for processing.
                //请此上下文处理此请求。
                // 已经出错的请求必须在这里路由,以检查应用程序定义的错误页面,
                // 因此不要将它们转发给应用程序进行处理。
                try {
                    if (!response.isErrorReportRequired()) {
                        context.getPipeline().getFirst().invoke(request, response);
                    }
                } 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 an error has occurred that prevents further I/O, don't waste time
                    // producing an error report that will never be read
                    AtomicBoolean result = new AtomicBoolean(false);
                    response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result);
                    if (result.get()) {
                        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);
                }
                //将当前线程上下文类加载器还原为调用{@link #bind(boolean, ClassLoader)}之前使用的原始类加载器。
                context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
            }
        }

根据指定的请求URI选择适当的子上下文来处理此请求。如果找不到匹配的上下文,则返回适当的HTTP错误。
主要处理了当前线程上下文类加载器,之后调用StandardContextValve的invoke。

StandardContextValve

     public final void invoke(Request request, Response response)
            throws IOException, ServletException {

            // Disallow any direct access to resources under WEB-INF or META-INF
            //禁止直接访问WEB-INF或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());
            }
            //调用StandardWrapperValve
            wrapper.getPipeline().getFirst().invoke(request, response);
        }

根据指定的请求URI选择适当的子包装器来处理此请求。如果找不到匹配的包装器,则返回适当的HTTP错误。

StandardWrapperValve

调用我们正在管理的servlet,并遵循有关servlet生命周期和SingleThreadModel支持的规则。

    public final void invoke(Request request, Response response)
            throws IOException, ServletException {

            // 初始化我们可能需要的局部变量
            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()) {
                //503
                response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                               sm.getString("standardContext.isUnavailable"));
                unavailable = true;
            }

            // Check for the servlet being marked unavailable
            //检查标记为不可用的servlet
            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);
                    //503
                    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                            sm.getString("standardWrapper.isUnavailable",
                                    wrapper.getName()));
                } else if (available == Long.MAX_VALUE) {
                    //404
                    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实例来处理这个请求
                    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);
                    //503
                    response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                               sm.getString("standardWrapper.isUnavailable",
                                            wrapper.getName()));
                } else if (available == Long.MAX_VALUE) {
                    //404
                    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();
            //request
            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
            //这也调用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 {
                                //doFilter
                                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) {
                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
            //释放分配的servlet实例
            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;

        }

这么长的方法有三个地方值得关注:

  1. wrapper.allocate(),分配一个servlet实例来处理这个请求
  2. ApplicationFilterFactory.createFilterChain(request, wrapper, servlet),为这个请求创建过滤器链
  3. filterChain.doFilter(request.getRequest(),response.getResponse()),执行过滤链,当所有的过滤器都执行完毕后调用 Servlet 的 service() 方法。

这三个部分后面再分析,这里有个疑问wrapper怎么来的?

wrapper怎么来的

解决这个问题要从Catalina读取Server.xml配制文件,组装StandardContext的时候,调用了StandardContext的addLifecycleListener方法,入参为:ContextConfig的实例。
StandardContext执行startInternal方法会调用下面代码:

    // Notify our interested LifecycleListeners
    fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
    protected void fireLifecycleEvent(String type, Object data) {
            LifecycleEvent event = new LifecycleEvent(this, type, data);
            for (LifecycleListener listener : lifecycleListeners) {
                listener.lifecycleEvent(event);
            }
        }

最终会调用到ContextConfig的lifecycleEvent方法,这里的生命周期事件为:CONFIGURE_START_EVENT-"configure_start",
所以会调用到ContextConfig的configureStart方法,再调用webConfig方法读取web.xml配置文件,
在继续调用到configureContext方法的时候,创建了wrapper。这里贴一段configureContext方法的代码:

    //略.....
     for (ServletDef servlet : webxml.getServlets().values()) {
                Wrapper wrapper = context.createWrapper();
                // Description is ignored
                // Display name is ignored
                // Icons are ignored

                // jsp-file gets passed to the JSP Servlet as an init-param

                if (servlet.getLoadOnStartup() != null) {
                    wrapper.setLoadOnStartup(servlet.getLoadOnStartup().intValue());
                }
                if (servlet.getEnabled() != null) {
                    wrapper.setEnabled(servlet.getEnabled().booleanValue());
                }
                wrapper.setName(servlet.getServletName());
                Map<String, String> params = servlet.getParameterMap();
                for (Entry<String, String> entry : params.entrySet()) {
                    wrapper.addInitParameter(entry.getKey(), entry.getValue());
                }
                wrapper.setRunAs(servlet.getRunAs());
                Set<SecurityRoleRef> roleRefs = servlet.getSecurityRoleRefs();
                for (SecurityRoleRef roleRef : roleRefs) {
                    wrapper.addSecurityReference(
                            roleRef.getName(), roleRef.getLink());
                }
                wrapper.setServletClass(servlet.getServletClass());
                MultipartDef multipartdef = servlet.getMultipartDef();
                if (multipartdef != null) {
                    if (multipartdef.getMaxFileSize() != null &&
                            multipartdef.getMaxRequestSize() != null &&
                            multipartdef.getFileSizeThreshold() != null) {
                        wrapper.setMultipartConfigElement(new MultipartConfigElement(
                                multipartdef.getLocation(),
                                Long.parseLong(multipartdef.getMaxFileSize()),
                                Long.parseLong(multipartdef.getMaxRequestSize()),
                                Integer.parseInt(
                                        multipartdef.getFileSizeThreshold())));
                    } else {
                        wrapper.setMultipartConfigElement(new MultipartConfigElement(
                                multipartdef.getLocation()));
                    }
                }
                if (servlet.getAsyncSupported() != null) {
                    wrapper.setAsyncSupported(
                            servlet.getAsyncSupported().booleanValue());
                }
                wrapper.setOverridable(servlet.isOverridable());
                context.addChild(wrapper);
            }
    //略.....

根据配置的servlet创建对应的wrapper。至于Servlet的初始化,加载等操作在StandardWrapper类中定义。

Servlet加载与初始化的流程

看一下Servlet加载与初始化的流程:
在执行StandardContext的startInternal方法时,会调用loadOnStartup方法:

    public boolean loadOnStartup(Container children[]) {

            // Collect "load on startup" servlets that need to be initialized
            //收集需要初始化的“启动时加载”servlet
            TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();
            for (int i = 0; i < children.length; i++) {
                Wrapper wrapper = (Wrapper) children[i];
                int loadOnStartup = wrapper.getLoadOnStartup();
                if (loadOnStartup < 0)
                    continue;
                Integer key = Integer.valueOf(loadOnStartup);
                ArrayList<Wrapper> list = map.get(key);
                if (list == null) {
                    list = new ArrayList<>();
                    map.put(key, list);
                }
                list.add(wrapper);
            }

            // Load the collected "load on startup" servlets
            //加载收集到的“启动时加载”servlet
            for (ArrayList<Wrapper> list : map.values()) {
                for (Wrapper wrapper : list) {
                    try {
                        wrapper.load();
                    } catch (ServletException e) {
                        getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",
                              getName(), wrapper.getName()), StandardWrapper.getRootCause(e));
                        // NOTE: load errors (including a servlet that throws
                        // UnavailableException from the init() method) are NOT
                        // fatal to application startup
                        // unless failCtxIfServletStartFails="true" is specified
                        if(getComputedFailCtxIfServletStartFails()) {
                            return false;
                        }
                    }
                }
            }
            return true;

        }

这里的入参就是上面配置的Servlet所封装的Wrapper。最后调用wrapper.load():

     /**
         * Load and initialize an instance of this servlet, if there is not already
         * at least one initialized instance.  This can be used, for example, to
         * load servlets that are marked in the deployment descriptor to be loaded
         * at server startup time.
         * <p>
         * <b>IMPLEMENTATION NOTE</b>:  Servlets whose classnames begin with
         * <code>org.apache.catalina.</code> (so-called "container" servlets)
         * are loaded by the same classloader that loaded this class, rather than
         * the classloader for the current web application.
         * This gives such classes access to Catalina internals, which are
         * prevented for classes loaded for web applications.
         *
         * @exception ServletException if the servlet init() method threw
         *  an exception
         * @exception ServletException if some other loading problem occurs
         */
        @Override
        public synchronized void load() throws ServletException {
            //加载Servlet
            instance = loadServlet();

            //如果没有初始化的话,就初始化Servlet
            if (!instanceInitialized) {
                initServlet(instance);
            }

            //JspServlet额外处理
            if (isJspServlet) {
                StringBuilder oname = new StringBuilder(getDomain());
                oname.append(":type=JspMonitor");
                oname.append(getWebModuleKeyProperties());
                oname.append(",name=");
                oname.append(getName());
                oname.append(getJ2EEKeyProperties());
                try {
                    jspMonitorON = new ObjectName(oname.toString());
                    Registry.getRegistry(null, null)
                        .registerComponent(instance, jspMonitorON, null);
                } catch( Exception ex ) {
                    log.info("Error registering JSP monitoring with jmx " +
                             instance);
                }
            }
        }

如果还没有至少一个初始化的实例,则加载并初始化这个servlet的实例。
例如,可以使用它来加载部署描述符中标记的servlet,这些servlet将在服务器启动时加载。
类名以org.apache.catalina开头的servlet。(所谓的“容器”servlet)由加载该类的同一个类加载器加载,而不是当前web应用程序的类加载器。
这使得此类类可以访问Catalina内部构件,而web应用程序加载的类则不能访问Catalina内部构件。

loadServlet()

     /**
         * Load and initialize an instance of this servlet, if there is not already
         * at least one initialized instance.  This can be used, for example, to
         * load servlets that are marked in the deployment descriptor to be loaded
         * at server startup time.
         * @return the loaded Servlet instance
         * @throws ServletException for a Servlet load error
         */
        public synchronized Servlet loadServlet() throws ServletException {

            // Nothing to do if we already have an instance or an instance pool
            if (!singleThreadModel && (instance != null))
                return instance;

            PrintStream out = System.out;
            if (swallowOutput) {
                SystemLogHandler.startCapture();
            }

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

                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) {
                    e = ExceptionUtils.unwrapInvocationTargetException(e);
                    ExceptionUtils.handleThrowable(e);
                    unavailable(null);

                    // Added extra log statement for Bugzilla 36630:
                    // https://bz.apache.org/bugzilla/show_bug.cgi?id=36630
                    if(log.isDebugEnabled()) {
                        log.debug(sm.getString("standardWrapper.instantiate", servletClass), e);
                    }

                    // Restore the context ClassLoader
                    throw new ServletException
                        (sm.getString("standardWrapper.instantiate", servletClass), e);
                }

                if (multipartConfigElement == null) {
                    MultipartConfig annotation =
                            servlet.getClass().getAnnotation(MultipartConfig.class);
                    if (annotation != null) {
                        multipartConfigElement =
                                new MultipartConfigElement(annotation);
                    }
                }

                // Special handling for ContainerServlet instances
                // Note: The InstanceManager checks if the application is permitted
                //       to load ContainerServlets
                if (servlet instanceof ContainerServlet) {
                    ((ContainerServlet) servlet).setWrapper(this);
                }

                classLoadTime=(int) (System.currentTimeMillis() -t1);

                if (servlet instanceof SingleThreadModel) {
                    if (instancePool == null) {
                        instancePool = new Stack<>();
                    }
                    singleThreadModel = true;
                }

                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;

        }

直接根绝servletClass name反射出一个实例,在执行initServlet方法,并且处理各种参数。

initServlet(instance)

    private synchronized void initServlet(Servlet servlet)
                throws ServletException {

            if (instanceInitialized && !singleThreadModel) return;

            // Call the initialization method of this servlet
            try {
                if( Globals.IS_SECURITY_ENABLED) {
                    boolean success = false;
                    try {
                        Object[] args = new Object[] { facade };
                        SecurityUtil.doAsPrivilege("init",
                                                   servlet,
                                                   classType,
                                                   args);
                        success = true;
                    } finally {
                        if (!success) {
                            // destroy() will not be called, thus clear the reference now
                            SecurityUtil.remove(servlet);
                        }
                    }
                } else {
                    servlet.init(facade);
                }

                instanceInitialized = true;
            } catch (UnavailableException f) {
                unavailable(f);
                throw f;
            } catch (ServletException f) {
                // If the servlet wanted to be unavailable it would have
                // said so, so do not call unavailable(null).
                throw f;
            } catch (Throwable f) {
                ExceptionUtils.handleThrowable(f);
                getServletContext().log("StandardWrapper.Throwable", f );
                // If the servlet wanted to be unavailable it would have
                // said so, so do not call unavailable(null).
                throw new ServletException
                    (sm.getString("standardWrapper.initException", getName()), f);
            }
        }

这里的重点在servlet.init(facade)。初始化Servlet,这个方法最初源自Servlet接口的init方法。


来源:https://www.jianshu.com/u/9632919f32c3

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Tomcat源码分析【十四】请求处理过程分析之Container

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏