2019-10-28 17:45  阅读(2011)
文章分类:Tomcat 源码分析 文章标签:TomcatTomcat 源码
©  原文作者:clawhub 原文地址:http://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)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> Tomcat源码分析【十四】请求处理过程分析之Container
上一篇
Tomcat源码分析【十三】请求处理过程分析之SocketProcessor
下一篇
Tomcat源码分析【十五】请求处理过程分析之分配Servlet实例处理请求