Tomcat8源码解析(二)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 2.Tomcat启动阶段 daemon.start(),tomcat的启动阶段分析 getServer().start(),方法启动Server,源码分析 services[i].start(),启动
2.Tomcat启动阶段
  • daemon.start(),tomcat的启动阶段分析
# 1.Bootstrap的start()方法
public void start()
    throws Exception {
    if( catalinaDaemon==null ) init();
    //实际上是执行了catalina的start()方法
    Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
    method.invoke(catalinaDaemon, (Object [])null);
}

# 1.Catalina的start()方法
public void start() {
    if (getServer() == null) {
        load();
    }
    if (getServer() == null) {
        log.fatal("Cannot start server. Server instance is not configured.");
        return;
    }
    long t1 = System.nanoTime();
    // Start the new server
    try {
        //启动Server(重点)
        getServer().start();
    } catch (LifecycleException e) {
        log.fatal(sm.getString("catalina.serverStartFail"), e);
        try {
            getServer().destroy();
        } catch (LifecycleException e1) {
            log.debug("destroy() failed for failed Server ", e1);
        }
        return;
    }

    long t2 = System.nanoTime();
    if(log.isInfoEnabled()) {
        log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
    }

    // Register shutdown hook 钩子
    if (useShutdownHook) {
        if (shutdownHook == null) {
            shutdownHook = new CatalinaShutdownHook();
        }
        Runtime.getRuntime().addShutdownHook(shutdownHook);
        // If JULI is being used, disable JULI's shutdown hook since
        // shutdown hooks run in parallel and log messages may be lost
        // if JULI's hook completes before the CatalinaShutdownHook()
        LogManager logManager = LogManager.getLogManager();
        if (logManager instanceof ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    false);
        }
    }
    if (await) {
        await();
        stop();
    }
}
  • getServer().start(),方法启动Server,源码分析
# 1.LifecycleBase的start()方法
@Override
public final synchronized void start() throws LifecycleException {
    if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
            LifecycleState.STARTED.equals(state)) {

        if (log.isDebugEnabled()) {
            Exception e = new LifecycleException();
            log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
        } else if (log.isInfoEnabled()) {
            log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
        }

        return;
    }

    if (state.equals(LifecycleState.NEW)) {
        init();
    } else if (state.equals(LifecycleState.FAILED)) {
        stop();
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
            !state.equals(LifecycleState.STOPPED)) {
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }

    try {
        setStateInternal(LifecycleState.STARTING_PREP, null, false);

        //启动子类的StandardServer(重点)
        startInternal();

        if (state.equals(LifecycleState.FAILED)) {
            // This is a 'controlled' failure. The component put itself into the
            // FAILED state so call stop() to complete the clean-up.
            stop();
        } else if (!state.equals(LifecycleState.STARTING)) {
            // Shouldn't be necessary but acts as a check that sub-classes are
            // doing what they are supposed to.
            invalidTransition(Lifecycle.AFTER_START_EVENT);
        } else {
            setStateInternal(LifecycleState.STARTED, null, false);
        }
    } catch (Throwable t) {
        // This is an 'uncontrolled' failure so put the component into the
        // FAILED state and throw an exception.
        ExceptionUtils.handleThrowable(t);
        setStateInternal(LifecycleState.FAILED, null, false);
        throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
    }
}

# 2.standardServer的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {

    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    setState(LifecycleState.STARTING);

    globalNamingResources.start();

    // Start our defined Services
    synchronized (servicesLock) {
        for (int i = 0; i < services.length; i++) {
            //启动services(重点)
            services[i].start();
        }
    }
}
Server的初始化start()方法,会先调用父类LifecycleBase的start()方法,然后再调用子类Server的startInternal()方法
这个调用的模式:父类start--->子类startInternal,在后面的services,connector,engine初始化是一样的模式。
  • services[i].start(),启动services,源码分析
# 1.standardService的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {

   if(log.isInfoEnabled())
        log.info(sm.getString("standardService.start.name", this.name));
    setState(LifecycleState.STARTING);

    //启动engine(重点)
    // Start our defined Container first
    if (engine != null) {
        synchronized (engine) {
            engine.start();
        }
    }

    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }

    //启动mapperListener
    mapperListener.start();

    // Start our defined Connectors second
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            try {
                // If it has already failed, don't try and start it
                if (connector.getState() != LifecycleState.FAILED) {
                    //启动connector(重点)
                    connector.start();
                }
            } catch (Exception e) {
                log.error(sm.getString(
                        "standardService.connector.startFailed",
                        connector), e);
            }
        }
    }
}
从services的启动分析,可以得到services的启动,会启动engine和connector。(executor、mapperListener)
  • connector.start(),启动Connector,源码分析
# 1.Connector的startInternal()方法
@Override
protected void startInternal() throws LifecycleException {

    // Validate settings before starting
    if (getPort() < 0) {
        throw new LifecycleException(sm.getString(
                "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
    }
    setState(LifecycleState.STARTING);
    try {
        //启动protocolHandler(重点)
        protocolHandler.start();
    } catch (Exception e) {
        throw new LifecycleException(
                sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
    }
}

# 2.AbstractProtocol下protocolHandler的启动start()方法
@Override
public void start() throws Exception {
    if (getLog().isInfoEnabled()) {
        getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
    }

    //启动endpoint
    endpoint.start();

    // Start async timeout thread
    asyncTimeout = new AsyncTimeout();
    Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
    int priority = endpoint.getThreadPriority();
    if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
        priority = Thread.NORM_PRIORITY;
    }
    timeoutThread.setPriority(priority);
    timeoutThread.setDaemon(true);
    timeoutThread.start();
}

# 3.AbstractEndpoint下endpoint的启动start()方法
public final void start() throws Exception {
    if (bindState == BindState.UNBOUND) {
        bind();
        bindState = BindState.BOUND_ON_START;
    }
    startInternal();
}
从connector的启动分析,可以得到connector的启动,会启动protocolHandler和endpoint
  • engine.start(),启动engine,源码分析
# 1.StandardEngine的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {

    // Log our server identification information
    if(log.isInfoEnabled())
        log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());

    // Standard container startup
    super.startInternal();
}

# 2.ContainerBase的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {

    // Start our subordinate components, if any
    logger = null;
    //日志处理
    getLogger();
    //有集群启动集群
    Cluster cluster = getClusterInternal();
    if (cluster instanceof Lifecycle) {
        ((Lifecycle) cluster).start();
    }
    //域处理
    Realm realm = getRealmInternal();
    if (realm instanceof Lifecycle) {
        ((Lifecycle) realm).start();
    }

    //启动所有子容器 StandardHost, StandardContext, StandardWrapper
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    for (int i = 0; i < children.length; i++) {
        results.add(startStopExecutor.submit(new StartChild(children[i])));
    }
    MultiThrowable multiThrowable = null;

    //开启线程启动子容器
    for (Future<Void> result : results) {
        try {
            //阻塞,让子容器启动完成再执行下面的代码
            result.get();
        } catch (Throwable e) {
            log.error(sm.getString("containerBase.threadedStartFailed"), e);
            if (multiThrowable == null) {
                multiThrowable = new MultiThrowable();
            }
            multiThrowable.add(e);
        }
    }
    if (multiThrowable != null) {
        throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                multiThrowable.getThrowable());
    }
    //启用Pipeline管道
    // Start the Valves in our pipeline (including the basic), if any
    if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).start();
    }
    //设置生命周期的状态starting,激发监听器listener:HostConfig,通过这个去启动Host(重要)
    setState(LifecycleState.STARTING);
    //开启线程
    threadStart();
}

# 3.StandardHost的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
    //设置错误报告
    // Set error report valve
    String errorValve = getErrorReportValveClass();
    if ((errorValve != null) && (!errorValve.equals(""))) {
        try {
            boolean found = false;
            Valve[] valves = getPipeline().getValves();
            for (Valve valve : valves) {
                if (errorValve.equals(valve.getClass().getName())) {
                    found = true;
                    break;
                }
            }
            if(!found) {
                Valve valve =
                    (Valve) Class.forName(errorValve).getConstructor().newInstance();
                getPipeline().addValve(valve);
            }
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            log.error(sm.getString(
                    "standardHost.invalidErrorReportValveClass",
                    errorValve), t);
        }
    }
    //再次调用父类ContainerBase
    super.startInternal();
}

# 4.LifecycleBase.setState(LifecycleState.STARTING); 改变生命周期的状态,激发监听器listener:HostConfig。
protected synchronized void setState(LifecycleState state) throws LifecycleException {
   setStateInternal(state, null, true);
}

private synchronized void setStateInternal(LifecycleState state,
          Object data, boolean check) throws LifecycleException {
    this.state = state;
    String lifecycleEvent = state.getLifecycleEvent();
    if (lifecycleEvent != null) {
        fireLifecycleEvent(lifecycleEvent, data);
    }
}

protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    for (LifecycleListener listener : lifecycleListeners) {
        //这个listener就是hostConfig(重点)
        listener.lifecycleEvent(event);
    }
}

# 5.HostConfig的start()
public void lifecycleEvent(LifecycleEvent event) {
    // Process the event that has occurred
    if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
        check();
    } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
        beforeStart();
    } else if (event.getType().equals(Lifecycle.START_EVENT)) {
        //执行hostConfig的start()方法
        start();
    } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
        stop();
    }
}

public void start() {
    ...
    //部署webapps
    if (host.getDeployOnStartup())
        deployApps();

}

# 6.部署webapps
protected void deployApps() {
   File appBase = host.getAppBaseFile();
   File configBase = host.getConfigBaseFile();
   String[] filteredAppPaths = filterAppPaths(appBase.list());

   //部署xml文件配置的server.xml  <host><context>...
   // Deploy XML descriptors from configBase
   deployDescriptors(configBase, configBase.list());

   //部署war包
   // Deploy WARs
   deployWARs(appBase, filteredAppPaths);

   //部署文件夹
   // Deploy expanded folders
   deployDirectories(appBase, filteredAppPaths);
}

# 7.部署文件夹deployDirectories()
protected void deployDirectories(File appBase, String[] files) {
    //发布文件夹
    if (files == null)
        return;

    //使用future和线程池的技术
    ExecutorService es = host.getStartStopExecutor();
    List<Future<?>> results = new ArrayList<>();

    for (int i = 0; i < files.length; i++) {

        if (files[i].equalsIgnoreCase("META-INF"))
            continue;
        if (files[i].equalsIgnoreCase("WEB-INF"))
            continue;
        File dir = new File(appBase, files[i]);
        if (dir.isDirectory()) {
            ContextName cn = new ContextName(files[i], false);

            if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
                continue;

            //submit(Runnable),接收一个Runnable,会返回一个Future
            //new DeployDirectory(重点)
            results.add(es.submit(new DeployDirectory(this, cn, dir)));
        }
    }

    //如果任务结束执行则返回null(会等待线程执行完)
    for (Future<?> result : results) {
        try {
            result.get();
        } catch (Exception e) {
            log.error(sm.getString(
                    "hostConfig.deployDir.threaded.error"), e);
        }
    }
}

//实现runnable接口
private static class DeployDirectory implements Runnable {

   private HostConfig config;
    private ContextName cn;
    private File dir;

    public DeployDirectory(HostConfig config, ContextName cn, File dir) {
        this.config = config;
        this.cn = cn;
        this.dir = dir;
    }

    @Override
    public void run() {
        //部署文件夹
        config.deployDirectory(cn, dir);
    }
}

# 8.部署文件夹deployDirectory()
protected void deployDirectory(ContextName cn, File dir) {

    long startTime = 0;
    // Deploy the application in this directory
    if( log.isInfoEnabled() ) {
        startTime = System.currentTimeMillis();
        log.info(sm.getString("hostConfig.deployDir",
                dir.getAbsolutePath()));
    }

    //拿到context
    Context context = null;
    File xml = new File(dir, Constants.ApplicationContextXml);
    File xmlCopy = new File(host.getConfigBaseFile(), cn.getBaseName() + ".xml");


    DeployedApplication deployedApp;
    boolean copyThisXml = isCopyXML();
    boolean deployThisXML = isDeployThisXML(dir, cn);

    try {
        if (deployThisXML && xml.exists()) {
            synchronized (digesterLock) {
                try {
                    //解析context节点
                    context = (Context) digester.parse(xml);
                } 
            }           
        } else if (!deployThisXML && xml.exists()) {
            context = new FailedContext();
        } else {
            context = (Context) Class.forName(contextClass).getConstructor().newInstance();
        }

        //实例化 ContextConfig,作为 LifecycleListener 添加到 Context 容器中
        //这和 StandardHost 的套路一样,都是使用 XXXConfig
        Class<?> clazz = Class.forName(host.getConfigClass());
        LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
        context.addLifecycleListener(listener);

        context.setName(cn.getName());
        context.setPath(cn.getPath());
        context.setWebappVersion(cn.getVersion());
        context.setDocBase(cn.getBaseName());

        //把context添加到子节点,然后启动context(重点)
        host.addChild(context);
    } 
}

从standardEngine的启动过程,可以看出,主要是启动standardHost。
然后通过监听器技术,启动HostConfig,进而解析webapps,启动context。

HostConfig的deployDirectory,主要做了几个工作:
1.使用 digester,或者反射实例化 StandardContext
2.实例化ContextConfig,并且为Context 容器注册事件监听器,和 StandardHost 的套路一样,借助 XXXConfig 完成容器的启动、停止工作

  1. 将当前 Context 实例作为子容器添加到Host 容器中,添加子容器的逻辑在 ContainerBase 中已经实现了,如果当前 Container 的状态是 STARTING_PREP 并且 startChildren 为 true,则还会启动子容器
  • StandardContext的startInternal()方法分析
# 1.StandardContext的startInternal()方法
 @Override
protected synchronized void startInternal() throws LifecycleException {
   //StandardContext启动

   if(log.isDebugEnabled())
       log.debug("Starting " + getBaseName());

   //发布这个状态,广播出去,让其他监听
   // Send j2ee.state.starting notification
   if (this.getObjectName() != null) {
       Notification notification = new Notification("j2ee.state.starting",
               this.getObjectName(), sequenceNumber.getAndIncrement());
       broadcaster.sendNotification(notification);
   }

   setConfigured(false);
   boolean ok = true;

   //启动命名空间资源
   // Currently this is effectively a NO-OP but needs to be called to
   // ensure the NamingResources follows the correct lifecycle
   if (namingResources != null) {
       namingResources.start();
   }

   //创建工作目录work
   // Post work directory
   postWorkDirectory();

   //加载资源
   // Add missing components as necessary
   if (getResources() == null) {   // (1) Required by Loader
       if (log.isDebugEnabled())
           log.debug("Configuring default Resources");

       try {
           setResources(new StandardRoot(this));
       } catch (IllegalArgumentException e) {
           log.error(sm.getString("standardContext.resourcesInit"), e);
           ok = false;
       }
   }
   if (ok) {
       resourcesStart();
   }

   //Webapp加载器
   if (getLoader() == null) {
       WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
       webappLoader.setDelegate(getDelegate());
       setLoader(webappLoader);
   }

   //初始化一个cookie
   // An explicit cookie processor hasn't been specified; use the default
   if (cookieProcessor == null) {
       cookieProcessor = new Rfc6265CookieProcessor();
   }

   //字符集的映射
   // Initialize character set mapper
   getCharsetMapper();

   //依赖关系处理
   // Validate required extensions
   boolean dependencyCheck = true;
   try {
       dependencyCheck = ExtensionValidator.validateApplication
           (getResources(), this);
   } catch (IOException ioe) {
       log.error(sm.getString("standardContext.extensionValidationError"), ioe);
       dependencyCheck = false;
   }

   if (!dependencyCheck) {
       // do not make application available if dependency check fails
       ok = false;
   }

   //用户命名属性,获取环境变量
   // Reading the "catalina.useNaming" environment variable
   String useNamingProperty = System.getProperty("catalina.useNaming");
   if ((useNamingProperty != null)
       && (useNamingProperty.equals("false"))) {
       useNaming = false;
   }

   if (ok && isUseNaming()) {
       if (getNamingContextListener() == null) {
           NamingContextListener ncl = new NamingContextListener();
           ncl.setName(getNamingContextName());
           ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
           addLifecycleListener(ncl);
           setNamingContextListener(ncl);
       }
   }

   // Standard container startup
   if (log.isDebugEnabled())
       log.debug("Processing standard container startup");


   // Binding thread
   ClassLoader oldCCL = bindThread();

   //发出一个生命周期事件,触发监听器:ContextConfig(重点)
   fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);

   //启动wrapper子节点(重点)
   // Start our child containers, if not already started
   for (Container child : findChildren()) {
       if (!child.getState().isAvailable()) {
           child.start();
       }
   }
}

# 2.ContextConfig的configureStart()方法
protected synchronized void configureStart() {    
    //解析web.xml(重点)
    //解析servlet,filter,listener
    webConfig();
}

protected void webConfig() {   
    //创建web.xml解析器
    WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
            context.getXmlValidation(), context.getXmlBlockExternal());

    Set<WebXml> defaults = new HashSet<>();
    defaults.add(getDefaultWebXmlFragment(webXmlParser));

    WebXml webXml = createWebXml();

    //解析web.xml
    InputSource contextWebXml = getContextWebXmlSource();
    if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
        ok = false;
    }

    ServletContext sContext = context.getServletContext();

    // Ordering is important here

    // Step 1. Identify all the JARs packaged with the application and those
    // provided by the container. If any of the application JARs have a
    // web-fragment.xml it will be parsed at this point. web-fragment.xml
    // files are ignored for container provided JARs.
    Map<String,WebXml> fragments = processJarsForWebFragments(webXml, webXmlParser);

    // Step 2. Order the fragments.
    Set<WebXml> orderedFragments = null;
    orderedFragments =
            WebXml.orderWebFragments(webXml, fragments, sContext);

    // Step 3. Look for ServletContainerInitializer implementations
    if (ok) {
        processServletContainerInitializers();
    }

    if  (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
        // Steps 4 & 5.
        processClasses(webXml, orderedFragments);
    }

    if (!webXml.isMetadataComplete()) {
        // Step 6. Merge web-fragment.xml files into the main web.xml
        // file.
        if (ok) {
            ok = webXml.merge(orderedFragments);
        }

        // Step 7. Apply global defaults
        // Have to merge defaults before JSP conversion since defaults
        // provide JSP servlet definition.
        webXml.merge(defaults);

        // Step 8. Convert explicitly mentioned jsps to servlets
        if (ok) {
            convertJsps(webXml);
        }

        // Step 9. Apply merged web.xml to Context
        if (ok) {
            //配置context
            configureContext(webXml);
        }
    } else {
        webXml.merge(defaults);
        convertJsps(webXml);
        configureContext(webXml);
    }

    if (context.getLogEffectiveWebXml()) {
        log.info("web.xml:\n" + webXml.toXml());
    }

    // Always need to look for static resources
    // Step 10. Look for static resources packaged in JARs
    if (ok) {
        // Spec does not define an order.
        // Use ordered JARs followed by remaining JARs
        Set<WebXml> resourceJars = new LinkedHashSet<>();
        for (WebXml fragment : orderedFragments) {
            resourceJars.add(fragment);
        }
        for (WebXml fragment : fragments.values()) {
            if (!resourceJars.contains(fragment)) {
                resourceJars.add(fragment);
            }
        }
        processResourceJARs(resourceJars);
        // See also StandardContext.resourcesStart() for
        // WEB-INF/classes/META-INF/resources configuration
    }

    // Step 11. Apply the ServletContainerInitializer config to the
    // context
    if (ok) {
        for (Map.Entry<ServletContainerInitializer,
                Set<Class<?>>> entry :
                    initializerClassMap.entrySet()) {
            if (entry.getValue().isEmpty()) {
                context.addServletContainerInitializer(
                        entry.getKey(), null);
            } else {
                context.addServletContainerInitializer(
                        entry.getKey(), entry.getValue());
            }
        }
    }

    // 指定 ServletContext 的相关参数   
    mergeParameters();

    // 调用 ServletContainerInitializer#onStartup() 
    for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
        initializers.entrySet()) {
        try {
            entry.getKey().onStartup(entry.getValue(),getServletContext());
        } catch (ServletException e) {
            log.error(sm.getString("standardContext.sciFail"), e);
            ok = false;
            break;
        }
    }

    //初始化 Filter
    if (ok) {
        if (!filterStart()) {
            log.error(sm.getString("standardContext.filterFail"));
            ok = false;
        }
    }
    
     //处理 Wrapper 容器(如果Servlet的loadOnStartup >= 0,便会在这一阶段完成 Servlet 的加载)
    if (ok) {
        if (!loadOnStartup(findChildren())){
            log.error(sm.getString("standardContext.servletFail"));
            ok = false;
        }
    }
}

StandardContext 和其他 Container 一样,也是重写了 startInternal 方法。由于涉及到 webapp 的启动流程,需要很多准备工作,比如使用 WebResourceRoot 加载资源文件、利用 Loader 加载 class、使用 JarScanner 扫描 jar 包,等等。
因此StandardContext 的启动逻辑比较复杂,这里描述下几个重要的步骤:

  1. 创建工作目录,比如$CATALINA_HOME\work\Catalina\localhost\examples;实例化 ContextServlet,应用程序拿到的是 ApplicationContext的外观模式
  2. 实例化 WebResourceRoot,默认实现类是 StandardRoot,用于读取 webapp 的文件资源
  3. 实例化 Loader 对象,Loader 是 tomcat 对于 ClassLoader 的封装,用于支持在运行期间热加载 class
  4. 发出 CONFIGURE_START_EVENT 事件,ContextConfig 会处理该事件,主要目的是从 webapp 中读取 servlet 相关的 Listener、Servlet、Filter 等
  5. 实例化 Sesssion 管理器,默认使用 StandardManager
  6. 调用 listenerStart,实例化 servlet 相关的各种 Listener,并且调用

ServletContextListener

  1. 处理 Filter
  2. 加载 Servlet
  • 触发 CONFIGURE_START_EVENT 事件,触发ContextConfig监听器

ContextConfig 它是一个 LifycycleListener,它在 Context 启动过程中是承担了一个非常重要的角色。StandardContext 会发出 CONFIGURE_START_EVENT 事件,而 ContextConfig 会处理该事件,主要目的是通过 web.xml 或者 Servlet3.0 的注解配置,读取 Servlet 相关的配置信息,比如 Filter、Servlet、Listener 等,其核心逻辑在 ContextConfig#webConfig() 方法中实现。
ContextConfig执行的重要步骤:

  1. 是通过 WebXmlParser 对 web.xml 进行解析,如果存在 web.xml 文件,则会把文件中定义的 Servlet、Filter、Listener 注册到 WebXml 实例中
  2. 如果没有 web.xml 文件,tomcat 会先扫描 WEB-INF/classes 目录下面的 class 文件,然后扫描 WEB-INF/lib 目录下面的 jar 包,解析字节码读取 servlet 相关的注解配置类,这里不得不吐槽下 serlvet3.0 注解,对 servlet 注解的处理相当重量级。tomcat 不会预先把该 class 加载到 jvm 中,而是通过解析字节码文件,获取对应类的一些信息,比如注解、实现的接口等
  • Step 9:往 Context 中添加子容器 Wrapper
# 1.context添加wrapper子节点
private void configureContext(WebXml webxml) {
    // 设置 Filter 定义
    for (FilterDef filter : webxml.getFilters().values()) {
        if (filter.getAsyncSupported() == null) {
            filter.setAsyncSupported("false");
        }
        context.addFilterDef(filter);
    }
    // 设置 FilterMapping,即 Filter 的 URL 映射 
    for (FilterMap filterMap : webxml.getFilterMappings()) {
        context.addFilterMap(filterMap);
    }
    // 往 Context 中添加子容器 Wrapper,即 Servlet
    for (ServletDef servlet : webxml.getServlets().values()) {
        Wrapper wrapper = context.createWrapper();
        // 省略若干代码。。。
        wrapper.setOverridable(servlet.isOverridable());
        context.addChild(wrapper);
    }
    // ......
}
  • 启动 StandardWrapper容器
# 1.StandardWrapper的startInternal()方法
@Override
protected synchronized void startInternal() throws LifecycleException {
    // 发出 j2ee.state.starting 事件通知
    if (this.getObjectName() != null) {
        Notification notification = new Notification("j2ee.state.starting",
                                                    this.getObjectName(),
                                                    sequenceNumber++);
        broadcaster.sendNotification(notification);
    }
    // ConainerBase 的启动逻辑
    super.startInternal();
    setAvailable(0L);

    // 发出 j2ee.state.running 事件通知
    if (this.getObjectName() != null) {
        Notification notification =
            new Notification("j2ee.state.running", this.getObjectName(), sequenceNumber++);
        broadcaster.sendNotification(notification);
    }
}

# 2.StandardWrapper的load()方法
@Override
public synchronized void load() throws ServletException {
    // 实例化 Servlet,并且调用 init 方法完成初始化
    instance = loadServlet();
    if (!instanceInitialized) {
        initServlet(instance);
    }

    if (isJspServlet) {
        // 处理 jsp Servlet
        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);
        }
    }
}
StandardWrapper 没有子容器,启动逻辑相对比较简单清晰,它重写了 startInternal 方法,主要是完成了 jmx 的事件通知,先后向 jmx 发出 starting、running 事件

由前面对 Context 容器的分析可知,Context 完成 Filter 初始化之后,如果 loadOnStartup >= 0 便会调用 load 方法加载 Wrapper 容器。StandardWrapper 使用 InstanceManager 实例化 Servlet,并且调用 Servlet 的 init 方法进行初始化,传入的 ServletConfig 是 StandardWrapperFacade 对象。

总结:
tomcat 实现了 javax.servlet.ServletContext 接口,在 Context 启动的时候会实例化该对象。由 Context 容器通过 web.xml 或者 扫描 class 字节码读取 servlet3.0 的注解配置,从而加载 webapp 定义的 Listener、Servlet、Filter 等 servlet 组件,但是并不会立即实例化对象。全部加载完毕之后,依次对 Listener、Filter、Servlet 进行实例化、并且调用其初始化方法,比如 ServletContextListener#contextInitialized()、Flter#init() 等

到此tomcat的启动阶段就已经完成了。使用的是责任链模式,一步一步的启动。
组件启动的顺序:
Server-->Service-->Engine-->Host-->Context-->Wrapper

  • tomcat初始化和启动流程图:
  • 在这里插入图片描述
3.Tomcat的web请求处理阶段
  • web请求的总体流程图
  • 在这里插入图片描述
由前面的tomcat总体架构可以知道,tomcat是由connector来接收用户的请求,然后再交由container处理。
通过跟踪connector的启动过程,先后启动protocolHandler,然后启动了endpoint,然后启动了Acceptor(用来接收请求)
  • 通过查看NioEndpoint的主要结构,可以看到该类有三个重要的内部类:Acceptor,Poller,SocketProcessor。
  • 在这里插入图片描述
# 1.NioEndpoint的startInternal()方法
@Override
public void startInternal() throws Exception {

    if (!running) {
        running = true;
        paused = false;

        processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                socketProperties.getProcessorCache());
        eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getEventCache());
        nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                socketProperties.getBufferPool());

        //创建工作者线程池
        // Create worker collection
        if ( getExecutor() == null ) {
            createExecutor();
        }

        initializeConnectionLatch();

        //启动poller线程,用来轮询检查新的请求
        // Start poller threads
        pollers = new Poller[getPollerThreadCount()];
        for (int i=0; i<pollers.length; i++) {
            pollers[i] = new Poller();
            Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
            pollerThread.setPriority(threadPriority);
            pollerThread.setDaemon(true);
            pollerThread.start();
        }

        //启动Acceptor线程,用来接收用户请求
        startAcceptorThreads();
    }
}

# 2.启动Acceptor线程
protected final void startAcceptorThreads() {
    //获取Acceptor线程数(默认是1)
    int count = getAcceptorThreadCount();
    //创建Acceptor数组
    acceptors = new Acceptor[count];

    for (int i = 0; i < count; i++) {
        //创建Acceptor对象,Acceptor继承Runnable
        acceptors[i] = createAcceptor();
        String threadName = getName() + "-Acceptor-" + i;
        acceptors[i].setThreadName(threadName);
        
        //创建Thread对象
        Thread t = new Thread(acceptors[i], threadName);
        t.setPriority(getAcceptorThreadPriority());
        t.setDaemon(getDaemon());
        
        //启动线程
        t.start();
    }
}
由上面的代码可以看出NioEndpoint在执行startInternal()方法时候,会启动Acceptor线程。Acceptor继承了Runnable,然后使用Thread启动了Acceptor线程。
  • Acceptor run()方法分析
# 1.Acceptor 用来接收请求
protected class Acceptor extends AbstractEndpoint.Acceptor {
   @Override
    public void run() {
        int errorDelay = 0;
        System.out.println("Acceptor 接收者开始执行");
        // Loop until we receive a shutdown command
        while (running) {
            // Loop if endpoint is paused
            while (paused && running) {
                state = AcceptorState.PAUSED;
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    // Ignore
                }
            }
            if (!running) {
                break;
            }
            state = AcceptorState.RUNNING;
            try {
                //if we have reached max connections, wait
                countUpOrAwaitConnection();

                SocketChannel socket = null;
                try {
                    //接收请求,拿到socket
                    socket = serverSock.accept();
                } catch (IOException ioe) {
                    // We didn't get a socket
                    countDownConnection();
                    if (running) {
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    } else {
                        break;
                    }
                }
                // Successful accept, reset the error delay
                errorDelay = 0;

                // Configure the socket
                if (running && !paused) {
                    //设置socket的一些属性
                    if (!setSocketOptions(socket)) {
                        closeSocket(socket);
                    }
                } else {
                    closeSocket(socket);
                }
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString("endpoint.accept.fail"), t);
            }
        }
        state = AcceptorState.ENDED;
    }
}

# 2.设置socket的一些属性
protected boolean setSocketOptions(SocketChannel socket) {
    // Process the connection
    try {
        //disable blocking, APR style, we are gonna be polling it
        socket.configureBlocking(false);
        Socket sock = socket.socket();
        socketProperties.setProperties(sock);

        //SocketChannel转化成nioChannel
        NioChannel channel = nioChannels.pop();
        if (channel == null) {
            SocketBufferHandler bufhandler = new SocketBufferHandler(
                    socketProperties.getAppReadBufSize(),
                    socketProperties.getAppWriteBufSize(),
                    socketProperties.getDirectBuffer());
            if (isSSLEnabled()) {  //SSL, https
                channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
            } else {
                //http1.1
                channel = new NioChannel(socket, bufhandler);
            }
        } else {
            channel.setIOChannel(socket);
            channel.reset();
        }
        //获取poller对象,注册channel(重要)
        getPoller0().register(channel);
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        try {
            log.error("",t);
        } catch (Throwable tt) {
            ExceptionUtils.handleThrowable(tt);
        }
        // Tell to close the socket
        return false;
    }
    return true;
}

# 3.poller对象,注册channel。Poller.register()方法
public void register(final NioChannel socket) {
    socket.setPoller(this);
    NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
    socket.setSocketWrapper(ka);
    ka.setPoller(this);
    ka.setReadTimeout(getSocketProperties().getSoTimeout());
    ka.setWriteTimeout(getSocketProperties().getSoTimeout());
    ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
    ka.setSecure(isSSLEnabled());
    ka.setReadTimeout(getConnectionTimeout());
    ka.setWriteTimeout(getConnectionTimeout());

    PollerEvent r = eventCache.pop();
    //生成poller, socket加入到even queue
    ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
    if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
    else r.reset(socket,ka,OP_REGISTER);
    addEvent(r);
}
通过查看Acceptor的run方法,可以看到拿到socket对象。(说明tomcat的底层是通过socket通信的)
然后就通过生成poller。Poller线程主要用于以较少的资源轮询已连接套接字以保持连接,当数据可用时转给工作线程。
  • Poller 轮询,检验是否有新的请求
# 1.Poller的run()方法
 @Override
public void run() {
    // Loop until destroy() is called
    while (true) {
           boolean hasEvents = false;
        try {
            if (!close) {
                //该方法遍历了eventqueue中所有的pollorEvent
                //然后依次调用pollorEvent的run方法
                //将socket注册到selector中
                hasEvents = events();
                if (wakeupCounter.getAndSet(-1) > 0) {               
                    keyCount = selector.selectNow();
                } else {
                    keyCount = selector.select(selectorTimeout);
                }
                wakeupCounter.set(0);
            }
            if (close) {
                events();
                timeout(0, false);
                try {
                    selector.close();
                } catch (IOException ioe) {
                    log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                }
                break;
            }
        } catch (Throwable x) {
            ExceptionUtils.handleThrowable(x);
            log.error("",x);
            continue;
        }
        //either we timed out or we woke up, process events first
        if ( keyCount == 0 ) hasEvents = (hasEvents | events());
    
        Iterator<SelectionKey> iterator =
            keyCount > 0 ? selector.selectedKeys().iterator() : null;
        // Walk through the collection of ready keys and dispatch
        // any active event.
        while (iterator != null && iterator.hasNext()) {
            SelectionKey sk = iterator.next();
            NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
            // Attachment may be null if another thread has called
            // cancelledKey()
            if (attachment == null) {
                iterator.remove();
            } else {
                iterator.remove();
                //处理(重点)
                processKey(sk, attachment);
            }
        }//while
         //process timeouts
         timeout(keyCount,hasEvents);
     }//while
      getStopLatch().countDown();
}

# 2.Poller,处理processKey
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
    try {
        if ( close ) {
            cancelledKey(sk);
        } else if ( sk.isValid() && attachment != null ) {
            if (sk.isReadable() || sk.isWritable() ) {
                if ( attachment.getSendfileData() != null ) {
                    processSendfile(sk,attachment, false);
                } else {
                    unreg(sk, attachment, sk.readyOps());
                    boolean closeSocket = false;
                    // Read goes before write
                    //读事件
                    if (sk.isReadable()) {
                        //处理socket(创建worker,重点)
                        if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
                            closeSocket = true;
                        }
                    }
                    //写事件
                    if (!closeSocket && sk.isWritable()) {
                        if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
                            closeSocket = true;
                        }
                    }
                    if (closeSocket) {
                        cancelledKey(sk);
                    }
                }
            }
        } else {
            //invalid key
            cancelledKey(sk);
        }
    } catch ( CancelledKeyException ckx ) {
        cancelledKey(sk);
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        log.error("",t);
    }
}
Poller线程主要用于以较少的资源轮询已连接套接字以保持连接,当数据可用时转给工作线程
通过对Poller的run方法跟踪,可以看到会创建SocketProcessor(worker)对socket的进一步处理。
  • SocketProcessor (worker) 处理socket过程。
# 1.AbstractEndpoint的processSocket()方法
//处理socket
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
        SocketEvent event, boolean dispatch) {
    try {
        if (socketWrapper == null) {
            return false;
        }
        //创建SocketProcessor处理器(worker)
        SocketProcessorBase<S> sc = processorCache.pop();
        if (sc == null) {
            sc = createSocketProcessor(socketWrapper, event);
        } else {
            sc.reset(socketWrapper, event);
        }
        //执行
        Executor executor = getExecutor();
        if (dispatch && executor != null) {
            executor.execute(sc);
        } else {
            sc.run();
        }
    } catch (RejectedExecutionException ree) {
        getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
        return false;
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        // This means we got an OOM or similar creating a thread, or that
        // the pool and its queue are full
        getLog().error(sm.getString("endpoint.process.fail"), t);
        return false;
    }
    return true;
}
  • SocketProcessor 的 doRun()分析。
# 1.SocketProcessor的doRun()方法
protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
    public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
        super(socketWrapper, event);
    }
    @Override
    protected void doRun() {
        NioChannel socket = socketWrapper.getSocket();
        SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
        try {
            int handshake = -1;
          
            if (handshake == 0) {
                SocketState state = SocketState.OPEN;
                // Process the request from this socket
                if (event == null) {
                    //处理socket(重点)
                    state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                } else {
                    state = getHandler().process(socketWrapper, event);
                }
                if (state == SocketState.CLOSED) {
                    close(socket, key);
                }
            } 
        }
    }
}

# 2.AbstractProtocol的ConnectionHandler的process()方法。(只贴出重点关注代码)
@Override
public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
    //拿到socket对象
    S socket = wrapper.getSocket();
    Processor processor = connections.get(socket);
    if (processor == null) {
        //创建Processor(重点)
        processor = getProtocol().createProcessor();
        register(processor);
    }
    //通过processor执行wrapper(重点)
    state = processor.process(wrapper, status);
    // Make sure socket/processor is removed from the list of current
    // connections
    connections.remove(socket);
    release(processor);
    return SocketState.CLOSED;
}

# 3.AbstractHttp11Protocol.createProcessor()方法。 创建Processor。
protected Processor createProcessor() {
  //构建Http11Processor
    Http11Processor processor = new Http11Processor(getMaxHttpHeaderSize(),
            getAllowHostHeaderMismatch(), getRejectIllegalHeaderName(), getEndpoint(),
            getMaxTrailerSize(), allowedTrailerHeaders, getMaxExtensionSize(),
            getMaxSwallowSize(), httpUpgradeProtocols, getSendReasonPhrase(),
            relaxedPathChars, relaxedQueryChars);
    //设置adapter适配器(重点)
    processor.setAdapter(getAdapter());

    //默认的keepAlive情况下,每个socket处理的最多的 请求次数
    processor.setMaxKeepAliveRequests(getMaxKeepAliveRequests());

    //开启keepAlive的Timeout
    processor.setConnectionUploadTimeout(getConnectionUploadTimeout());

    //http当遇到文件上传时 默认超时时间(300*1000)
    processor.setDisableUploadTimeout(getDisableUploadTimeout());

    //当http请求的body size超过这个值时,通过gzip进行压缩
    processor.setCompressionMinSize(getCompressionMinSize());

    //http请求是否开启compression处理,gzip压缩
    processor.setCompression(getCompression());
    processor.setNoCompressionUserAgents(getNoCompressionUserAgents());
    //http body里面的内容是“text/html,text/xml,text/plain”
    //才会进行压缩处理
    processor.setCompressibleMimeTypes(getCompressibleMimeTypes());
    processor.setRestrictedUserAgents(getRestrictedUserAgents());

    //最大的post处理尺寸的大小 4*1000
    processor.setMaxSavePostSize(getMaxSavePostSize());
    processor.setServer(getServer());
    processor.setServerRemoveAppProvidedValues(getServerRemoveAppProvidedValues());
    return processor;
}

# 4.通过processor执行wrapper(AbstractProcessorLight.process()方法)
@Override
public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
        throws IOException {
    SocketState state = SocketState.CLOSED;
    Iterator<DispatchType> dispatches = null;
    do {
        if (dispatches != null) {
            DispatchType nextDispatch = dispatches.next();
            state = dispatch(nextDispatch.getSocketStatus());
        } else if (status == SocketEvent.DISCONNECT) {
            // Do nothing here, just wait for it to get recycled
        } else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
            state = dispatch(status);
            if (state == SocketState.OPEN) {   
                //执行service方法,处理socket(重点)
                state = service(socketWrapper);
            }
        } else if (status == SocketEvent.OPEN_WRITE) {
            // Extra write event likely after async, ignore
            state = SocketState.LONG;
        } else if (status == SocketEvent.OPEN_READ){
            state = service(socketWrapper);
        } else {           
            state = SocketState.CLOSED;
        }
        if (dispatches == null || !dispatches.hasNext()) {
            // Only returns non-null iterator if there are
            // dispatches to process.
            dispatches = getIteratorAndClearDispatches();
        }
    } while (state == SocketState.ASYNC_END ||
            dispatches != null && state != SocketState.CLOSED);
    return state;
}

# 5.Http11Processor的service()方法(只保留重点代码)
@Override
public SocketState service(SocketWrapperBase<?> socketWrapper){
    //通过adapter处理请求(重点)
      getAdapter().service(request, response);
}
通过上面的代码分析,SocketProcessor 在处理socket对象,最终是通过调用getAdapter().service(request, response)方法处理。
  • 下面进入到getAdapter().service(request, response)方法分析。
# 1.CoyoteAdapter的service()方法
@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)  
        throws Exception {  //接收到所有的请求
    //转换request和response
    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);
    if (request == null) {
        //通过connector创建request和response
        request = connector.createRequest();
        request.setCoyoteRequest(req);
        response = connector.createResponse();
        response.setCoyoteResponse(res);
        //link将request和response连接起来
        request.setResponse(response);
        response.setRequest(request);
        // Set as notes
        req.setNote(ADAPTER_NOTES, request);
        res.setNote(ADAPTER_NOTES, response);
        //设置URI的编码
        req.getParameters().setQueryStringCharset(connector.getURICharset());
    }
    if (connector.getXpoweredBy()) {
        response.addHeader("X-Powered-By", POWERED_BY);
    }
    boolean async = false;
    boolean postParseSuccess = false;
    req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());

    try {

        // Parse and set Catalina and configuration specific
        // request parameters
        //在map里面解析业务请求(重要)
        postParseSuccess = postParseRequest(req, request, res, response);
        if (postParseSuccess) {
            //设置异步支持(getContainer()拿到的是engine)
            //check valves if we support async
            request.setAsyncSupported(
                    connector.getService().getContainer().getPipeline().isAsyncSupported());
            // Calling the container
            //执行pipeline管道(invoke)standardEngineValve.invoke (重点)
            connector.getService().getContainer().getPipeline().getFirst().invoke(
                    request, response);
        }
        if (request.isAsync()) {       
         
        } else {
            //请求和响应完成
            request.finishRequest();
            response.finishResponse();
        }
    }
}

# 2.standardEngineValve.invoke()方法
@Override
public final void invoke(Request request, Response response)
    throws IOException, ServletException {
    //获取StandardHost对象
    // Select the Host to be used for this Request
    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());
    }
    //执行standardHostValue.invoke()方法(重点)
    // Ask this Host to process this request
    host.getPipeline().getFirst().invoke(request, response);
}

# 3.standardHostValue.invoke()方法
@Override
public final void invoke(Request request, Response response)
    throws IOException, ServletException {
    //获取standardContext
    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 {
        context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
        if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
            return;
        }
        try {
            if (!asyncAtStart || asyncDispatching) {
                //执行standardContextValue.invoke()的方法(重点)
                context.getPipeline().getFirst().invoke(request, response);
            } 
        }        
    } 
}

# 4.standardContextValue.invoke()方法
@Override
public final void invoke(Request request, Response response)
    throws IOException, ServletException {    
    //获取StandardWrapper
    // 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;
    }

    if (request.isAsyncSupported()) {
        request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
    }
    //执行standardWrapperValue.invoke()的方法(重点)
    wrapper.getPipeline().getFirst().invoke(request, response);
}

# 5.standardWrapperValue.invoke()方法
//最终找到servlet处理
@Override
public final void invoke(Request request, Response response)
    throws IOException, ServletException {

    // Initialize local variables we may need
    boolean unavailable = false;
    Throwable throwable = null;
    // This should be a Request attribute...
    long t1=System.currentTimeMillis();
    //增加请求次数,CAS
    requestCount.incrementAndGet();
    StandardWrapper wrapper = (StandardWrapper) getContainer();

    //获取servlet对象
    Servlet servlet = null;
    Context context = (Context) wrapper.getParent();

    // Check for the application being marked unavailable
    if (!context.getState().isAvailable()) {
        response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                       sm.getString("standardContext.isUnavailable"));
        unavailable = true;
    }

    // Check for the servlet being marked unavailable
    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);
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                    sm.getString("standardWrapper.isUnavailable",
                            wrapper.getName()));
        } else if (available == Long.MAX_VALUE) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND,
                    sm.getString("standardWrapper.notFound",
                            wrapper.getName()));
        }
        unavailable = true;
    }

    //Servlet默认的是在第一次请求的时候实例化
    // Allocate a servlet instance to process this request
    try {
        if (!unavailable) {
            //获取不到,再分配加载一个
            servlet = wrapper.allocate();
        }
    } catch (UnavailableException e) {
        container.getLogger().error(
                sm.getString("standardWrapper.allocateException",
                        wrapper.getName()), e);
        long available = wrapper.getAvailable();
        if ((available > 0L) && (available < Long.MAX_VALUE)) {
            response.setDateHeader("Retry-After", available);
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                       sm.getString("standardWrapper.isUnavailable",
                                    wrapper.getName()));
        } else if (available == Long.MAX_VALUE) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND,
                       sm.getString("standardWrapper.notFound",
                                    wrapper.getName()));
        }
    } catch (ServletException e) {
        container.getLogger().error(sm.getString("standardWrapper.allocateException",
                         wrapper.getName()), StandardWrapper.getRootCause(e));
        throwable = e;
        exception(request, response, e);
    } catch (Throwable e) {
        ExceptionUtils.handleThrowable(e);
        container.getLogger().error(sm.getString("standardWrapper.allocateException",
                         wrapper.getName()), e);
        throwable = e;
        exception(request, response, e);
        servlet = null;
    }

    //获取path
    MessageBytes requestPathMB = request.getRequestPathMB();
    DispatcherType dispatcherType = DispatcherType.REQUEST;
    if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
    request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
    request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
            requestPathMB);
    // Create the filter chain for this request
    ApplicationFilterChain filterChain =
            ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

    //执行相应的filter过滤器链
    // Call the filter chain for this request
    // NOTE: This also calls the servlet's service() method
    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 | CloseNowException e) {
        if (container.getLogger().isDebugEnabled()) {
            container.getLogger().debug(sm.getString(
                    "standardWrapper.serviceException", wrapper.getName(),
                    context.getName()), 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
    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);
        }
    }
}
通过对CoyoteAdapter的service()方法分析,可以知道他是一步一步的调用方法。
StandardEngineValue-->StandardHostValue-->StandardContextValue-->StandardWrapperValue的invoke方法。
目录
相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
17天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
22天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
50 12
|
1月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
1月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
54 3
|
2月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
63 5
|
2月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
148 5
|
2月前
|
安全 应用服务中间件 网络安全
Tomcat如何配置PFX证书?
【10月更文挑战第2天】Tomcat如何配置PFX证书?
238 7
|
2月前
|
存储 算法 应用服务中间件
Tomcat如何配置JKS证书?
【10月更文挑战第2天】Tomcat如何配置JKS证书?
370 4

推荐镜像

更多
下一篇
DataWorks