Tomcat start过程分析

简介: 开篇 这篇文章主要是把Tomcat的start启动过程的时序图和源码进行结合,加深一下印象,同时在分析源码过程中会分析下Tomcat的代码设计结构供自己提升抽象能力,想更好的阅读这部分代码提前了解以下问题。

开篇

 这篇文章主要是把Tomcat的start启动过程的时序图和源码进行结合,加深一下印象,同时在分析源码过程中会分析下Tomcat的代码设计结构供自己提升抽象能力,想更好的阅读这部分代码提前了解以下问题。

  • 1、如果代码上无法直接串联起来那么就通过源码debug发现调用栈。
  • 2、容器类的启动过程跟类的继承实现关系非常大所以需要好好研究基类。
  • 3、容器的start过程类似于串联调用的过程,这点有助于理解代码逻辑。
  • 4、每个容器的启动过程不做容器启动细节分析,这部分分析后续补充。


Tomcat启动过程时序图

img_5000ebed98574d760149b40488d94dfb.png
Tomcat 启动过程流程图

说明:

  • Tomcat的整个服务器启动包括初始化过程和启动过程
  • 该篇文章主要是分析start()初始化过程


Tomcat启动过程 - Bootstrap启动

  • Bootstrap通过反射调用Catalina的start()接口启动Catalina对象。
public final class Bootstrap {

    public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }
}


Tomcat启动过程 - Catalina启动

  • Catalina调用StandardServer的基类LifecycleBase的start()接口启动StandardService。
public class Catalina {

    public void start() {

        if (getServer() == null) {
            load();
        }

        // 启动Server的服务
        try {
            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;
        }

        // 省略相关代码
    }
}


Tomcat启动过程 - Server启动

  • StandardServer的启动过程通过调用基类LifecycleBase的start()接口

  • StandardServer的内部通过调用startInternal()启动自身。

  • StandardServer的内部通过services[i].start()启动Service对象。


    img_fb598a45b1401ed2d2a85f6a830c397a.png
    StandardServer
public final class StandardServer extends LifecycleMBeanBase implements Server {

    @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[i].start();
            }
        }
    }
}


Tomcat启动过程 - Service启动

  • StandardService的启动过程通过调用基类LifecycleBase的start()接口

  • StandardService的内部通过调用startInternal()启动自身。

  • StandardServer的内部通过engine.start()启动Engine对象。

  • StandardServer的内部通过executor.start()启动Executor对象。

  • StandardServer的内部通过mapperListener.start()启动MapperListener对象。

  • StandardServer的内部通过connector.start()启动Connector对象。

img_804c0abec0d2c45fe635747a878882e0.png
StandardService
public class StandardService extends LifecycleMBeanBase implements Service {

    @Override
    protected void startInternal() throws LifecycleException {

        setState(LifecycleState.STARTING);

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

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

        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.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }
}


Tomcat启动过程 - ContainerBase

  • ContainerBase的startInternal是所有容器父容器,内部启动过程都会执行。

  • ContainerBase的startInternal()方法内部负责启动Cluster对象。

  • ContainerBase的startInternal()方法内部负责启动Realm对象。

  • ContainerBase的startInternal()方法内部负责启动子容器Container对象。

  • ContainerBase的startInternal()方法内部负责处理链条pipeline对象。

  • ContainerBase的startInternal()方法内部负责处理启动线程threadStart。

img_f57bc299d860ba68f02dfce470ce9777.png
ContainerBase
public interface Lifecycle {

    public static final String BEFORE_INIT_EVENT = "before_init";
    public static final String AFTER_INIT_EVENT = "after_init";
    public static final String START_EVENT = "start";
    public static final String BEFORE_START_EVENT = "before_start";
    public static final String AFTER_START_EVENT = "after_start";
    public static final String STOP_EVENT = "stop";
    public static final String BEFORE_STOP_EVENT = "before_stop";
    public static final String AFTER_STOP_EVENT = "after_stop";
    public static final String AFTER_DESTROY_EVENT = "after_destroy";
    public static final String BEFORE_DESTROY_EVENT = "before_destroy";
    public static final String PERIODIC_EVENT = "periodic";
    public static final String CONFIGURE_START_EVENT = "configure_start";
    public static final String CONFIGURE_STOP_EVENT = "configure_stop";


    public void addLifecycleListener(LifecycleListener listener);
    public LifecycleListener[] findLifecycleListeners();
    public void removeLifecycleListener(LifecycleListener listener);
    public void init() throws LifecycleException;
    public void start() throws LifecycleException;
    public void stop() throws LifecycleException;
    public void destroy() throws LifecycleException;
    public LifecycleState getState();
    public String getStateName();

    public interface SingleUse {
    }
}


public abstract class LifecycleBase implements Lifecycle {

    public final synchronized void init() throws LifecycleException {
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }

        try {
            setStateInternal(LifecycleState.INITIALIZING, null, false);
            initInternal();
            setStateInternal(LifecycleState.INITIALIZED, null, false);
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            setStateInternal(LifecycleState.FAILED, null, false);
            throw new LifecycleException(
                    sm.getString("lifecycleBase.initFail",toString()), t);
        }
    }


    protected abstract void initInternal() throws LifecycleException;

    @Override
    public final synchronized void start() throws LifecycleException {

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

    protected abstract void startInternal() throws LifecycleException;
}


public abstract class ContainerBase extends LifecycleMBeanBase
        implements Container {

    @Override
    protected synchronized void startInternal() throws LifecycleException {

        // 启动下级组件
        logger = null;
        getLogger();
        Cluster cluster = getClusterInternal();
        if (cluster instanceof Lifecycle) {
            ((Lifecycle) cluster).start();
        }
        Realm realm = getRealmInternal();
        if (realm instanceof Lifecycle) {
            ((Lifecycle) realm).start();
        }

        // 启动所有子容器
        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 = new MultiThrowable();

        for (Future<Void> result : results) {
            try {
                result.get();
            } catch (Throwable e) {
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
                multiThrowable.add(e);
            }

        }
        if (multiThrowable.size() > 0) {
            throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                    multiThrowable.getThrowable());
        }

        // 启动组件的处理链的组件
        if (pipeline instanceof Lifecycle) {
            ((Lifecycle) pipeline).start();
        }

        // 设置容器处理状态
        setState(LifecycleState.STARTING);

        // 启动线程
        threadStart();
    }


    private static class StartChild implements Callable<Void> {

        private Container child;

        public StartChild(Container child) {
            this.child = child;
        }

        @Override
        public Void call() throws LifecycleException {
            child.start();
            return null;
        }
    }


    private static class StopChild implements Callable<Void> {

        private Container child;

        public StopChild(Container child) {
            this.child = child;
        }

        @Override
        public Void call() throws LifecycleException {
            if (child.getState().isAvailable()) {
                child.stop();
            }
            return null;
        }
    }

}


Tomcat启动过程 - 容器对象的启动过程

  • 了解这个过程很重要,很重要,很重要!!!
  • 容器对象主要包括Engine、Host、Context、Wrapper。
  • 容器对象启动过程类似串联启动的过程,Engine启动带动Host,Host启动带动Context、Context启动带动Wrapper。
  • 容器都继承基类ContainerBase,通用的方法和执行过程都在该类中定义。


Tomcat启动过程 - Engine启动

  • Engine启动过程主要是通过父类ContainerBase的startInternal()实现的。

  • ContainerBase的startInternal()通过startStopExecutor.submit(new StartChild(children[i]))启动host对象

  • Engine启动会调用ContainerBase的startInternal()启动自身的处理链pipeline。

img_c372208919460dacf265b0d9a7869590.png
StandardEngine
public class StandardEngine extends ContainerBase implements Engine {

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


Tomcat启动过程 - Host启动

  • Engine的StartChild()方法内部通过call()执行Host对象的启动。

  • Host对象继承自LifecycleBase类,start()方法会执行LifecycleBase的start()方法。

  • LifecycleBase的start()方法先判断Host的init()方法执行后再执行start()方法。

  • LifecycleBase的start()方法内部执行初始化Host的子容器也就是Context。

img_150c878474f1343fc5ae0fd522b0a56d.png
StandardHost
public class StandardHost extends ContainerBase implements Host {

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


Tomcat启动过程 - Context启动

  • Host的StartChild()方法内部通过call()执行Context对象的启动。

  • Context对象继承自LifecycleBase类,start()方法会执行LifecycleBase的start()方法。

  • LifecycleBase的start()方法先判断Context的init()方法执行后再执行start()方法。

  • LifecycleBase的start()方法内部初始化Context的子容器也就是Wrapper。

img_e5a7ad9cf8948eb27f7944d11e526200.png
StandardContext
public class StandardContext extends ContainerBase
        implements Context, NotificationEmitter {

    protected synchronized void startInternal() throws LifecycleException {

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

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

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

        // 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) {
            dependencyCheck = false;
        }

        if (!dependencyCheck) {
            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);
            }
        }

        // Binding thread
        ClassLoader oldCCL = bindThread();

        try {
            if (ok) {
                // Start our subordinate components, if any
                Loader loader = getLoader();
                if (loader instanceof Lifecycle) {
                    ((Lifecycle) loader).start();
                }

                // since the loader just started, the webapp classloader is now
                // created.
                setClassLoaderProperty("clearReferencesRmiTargets",
                        getClearReferencesRmiTargets());
                setClassLoaderProperty("clearReferencesStopThreads",
                        getClearReferencesStopThreads());
                setClassLoaderProperty("clearReferencesStopTimerThreads",
                        getClearReferencesStopTimerThreads());
                setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread",
                        getClearReferencesHttpClientKeepAliveThread());
                setClassLoaderProperty("clearReferencesObjectStreamClassCaches",
                        getClearReferencesObjectStreamClassCaches());

                // By calling unbindThread and bindThread in a row, we setup the
                // current Thread CCL to be the webapp classloader
                unbindThread(oldCCL);
                oldCCL = bindThread();

                // Initialize logger again. Other components might have used it
                // too early, so it should be reset.
                logger = null;
                getLogger();

                Realm realm = getRealmInternal();
                if(null != realm) {
                    if (realm instanceof Lifecycle) {
                        ((Lifecycle) realm).start();
                    }

                    CredentialHandler safeHandler = new CredentialHandler() {
                        @Override
                        public boolean matches(String inputCredentials, String storedCredentials) {
                            return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials);
                        }

                        @Override
                        public String mutate(String inputCredentials) {
                            return getRealmInternal().getCredentialHandler().mutate(inputCredentials);
                        }
                    };
                    context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler);
                }

                // Notify our interested LifecycleListeners
                fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);

                // Start our child containers, if not already started
                for (Container child : findChildren()) {
                    if (!child.getState().isAvailable()) {
                        child.start();
                    }
                }

                if (pipeline instanceof Lifecycle) {
                    ((Lifecycle) pipeline).start();
                }

                // Acquire clustered manager
                Manager contextManager = null;
                Manager manager = getManager();
                if (manager == null) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("standardContext.cluster.noManager",
                                Boolean.valueOf((getCluster() != null)),
                                Boolean.valueOf(distributable)));
                    }
                    if ( (getCluster() != null) && distributable) {
                        try {
                            contextManager = getCluster().createManager(getName());
                        } catch (Exception ex) {
                            log.error("standardContext.clusterFail", ex);
                            ok = false;
                        }
                    } else {
                        contextManager = new StandardManager();
                    }
                }

                // Configure default manager if none was specified
                if (contextManager != null) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("standardContext.manager",
                                contextManager.getClass().getName()));
                    }
                    setManager(contextManager);
                }

                if (manager!=null && (getCluster() != null) && distributable) {
                    //let the cluster know that there is a context that is distributable
                    //and that it has its own manager
                    getCluster().registerManager(manager);
                }
            }

            if (!getConfigured()) {
                log.error(sm.getString("standardContext.configurationFail"));
                ok = false;
            }

            // We put the resources into the servlet context
            if (ok)
                getServletContext().setAttribute
                    (Globals.RESOURCES_ATTR, getResources());

            if (ok ) {
                if (getInstanceManager() == null) {
                    javax.naming.Context context = null;
                    if (isUseNaming() && getNamingContextListener() != null) {
                        context = getNamingContextListener().getEnvContext();
                    }
                    Map<String, Map<String, String>> injectionMap = buildInjectionMap(
                            getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources());
                    setInstanceManager(new DefaultInstanceManager(context,
                            injectionMap, this, this.getClass().getClassLoader()));
                }
                getServletContext().setAttribute(
                        InstanceManager.class.getName(), getInstanceManager());
                InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager());
            }

            // Create context attributes that will be required
            if (ok) {
                getServletContext().setAttribute(
                        JarScanner.class.getName(), getJarScanner());
            }

            // Set up the context init params
            mergeParameters();

            // Call ServletContainerInitializers
            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;
                }
            }

            // Configure and call application event listeners
            if (ok) {
                if (!listenerStart()) {
                    log.error(sm.getString("standardContext.listenerFail"));
                    ok = false;
                }
            }

            if (ok) {
                checkConstraintsForUncoveredMethods(findConstraints());
            }

            try {
                // Start manager
                Manager manager = getManager();
                if (manager instanceof Lifecycle) {
                    ((Lifecycle) manager).start();
                }
            } catch(Exception e) {
                ok = false;
            }

            // Configure and call application filters
            if (ok) {
                if (!filterStart()) {
                    ok = false;
                }
            }

            // Load and initialize all "load on startup" servlets
            if (ok) {
                if (!loadOnStartup(findChildren())){
                    ok = false;
                }
            }

            // Start ContainerBackgroundProcessor thread
            super.threadStart();
        } finally {
            // Unbinding thread
            unbindThread(oldCCL);
        }

        // Set available status depending upon startup success
        if (ok) {
            if (log.isDebugEnabled())
                log.debug("Starting completed");
        } else {
        }

        startTime=System.currentTimeMillis();

        // Send j2ee.state.running notification
        if (ok && (this.getObjectName() != null)) {
            Notification notification =
                new Notification("j2ee.state.running", this.getObjectName(),
                                 sequenceNumber.getAndIncrement());
            broadcaster.sendNotification(notification);
        }

        getResources().gc();

        // Reinitializing if something went wrong
        if (!ok) {
            setState(LifecycleState.FAILED);
        } else {
            setState(LifecycleState.STARTING);
        }
    }
}


Tomcat启动过程 - Wrapper启动

  • Context的StartChild()方法内部通过call()执行Wrapper对象的启动。

  • Wrapper对象继承自LifecycleBase类,start()方法会执行LifecycleBase的start()方法。

  • LifecycleBase的start()方法先判断Context的init()方法执行后再执行start()方法。

img_685fd298984d7b5295e45960421f6a04.png
StandardWrapper
public class StandardWrapper extends ContainerBase
    implements ServletConfig, Wrapper, NotificationEmitter {

    protected synchronized void startInternal() throws LifecycleException {

        // Send j2ee.state.starting notification
        if (this.getObjectName() != null) {
            Notification notification = new Notification("j2ee.state.starting",
                                                        this.getObjectName(),
                                                        sequenceNumber++);
            broadcaster.sendNotification(notification);
        }

        // Start up this component
        super.startInternal();

        setAvailable(0L);

        // Send j2ee.state.running notification
        if (this.getObjectName() != null) {
            Notification notification =
                new Notification("j2ee.state.running", this.getObjectName(),
                                sequenceNumber++);
            broadcaster.sendNotification(notification);
        }
    }
}


Tomcat启动过程 - Connector启动

  • Connector继承自基类LifecycleMbeanBase类

  • StandardService调用Connector的start()方法启动Connector,最终调用Connector的startInternal()方法。

  • Connector的startInternal()方法串联执行protocolHandler的start()方法。


    img_2c37b75a35e28372704a3d4cd007397b.png
    image.png
public class Connector extends LifecycleMBeanBase  {

    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.start();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }
}


Tomcat启动过程 - AbstractProtocol启动

  • AbstractProtocol的启动过程主要启动EndPoint的监听操作
  • EndPoint的启动过程就暂时不分析了。


    img_13b5a4b7b96aa1e8ebe6ac392b049172.png
    AbstractProtocol
public abstract class AbstractProtocol<S> implements ProtocolHandler,
        MBeanRegistration {

    @Override
    public void start() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
        }

        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();
    }
}
目录
相关文章
|
7月前
|
设计模式 安全 Java
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
【分布式技术专题】「Tomcat技术专题」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)
112 0
|
4月前
|
Arthas Java 应用服务中间件
一次Tomcat返回404的分析
一个Web应用部署在阿里云EDAS上,使用Tomcat 7.0.59.3,在测试环境遭遇所有接口返回404的问题,而生产环境正常。测试与生产环境主要差异在于Apollo配置不同。通过Arthas工具监控,确认Spring已正确加载Controller,并且请求未进入Spring或Filter处理流程。进一步分析发现,Tomcat内部处理流程中设置了404状态码,最终定位到`org.apache.coyote.http11.AbstractHttp11Processor.process`方法存在问题。通过对代码逻辑的分析,确定原因是请求URL路径不正确。修正URL路径后问题得到解决。
94 1
一次Tomcat返回404的分析
|
6月前
|
XML 应用服务中间件 Android开发
【已解决】eclipse导入项目出错 Server Tomcat v7.0 Server at localhost failed to start
【已解决】eclipse导入项目出错 Server Tomcat v7.0 Server at localhost failed to start
57 0
|
7月前
|
Java 应用服务中间件 Maven
解决“Unable to start embedded Tomcat“错误的完整指南
通过逐步检查以上问题,你应该能够解决 "Unable to start embedded Tomcat" 错误,并使Tomcat成功启动。
1817 1
解决“Unable to start embedded Tomcat“错误的完整指南
|
应用服务中间件
Tomcat报错:The required Server component failed to start so Tomcat is unable to start
Tomcat报错:The required Server component failed to start so Tomcat is unable to start
241 0
|
Java 应用服务中间件 容器
Tomcat报错 严重: A child container failed during start
Tomcat报错 严重: A child container failed during start
191 0
|
7月前
|
存储 负载均衡 NoSQL
【分布式技术架构】「Tomcat技术专题」 探索Tomcat集群架构原理和开发分析指南
【分布式技术架构】「Tomcat技术专题」 探索Tomcat集群架构原理和开发分析指南
149 1
|
应用服务中间件 Android开发
Server Tomcat v9.0 Server at localhost failed to start问题的解决
Server Tomcat v9.0 Server at localhost failed to start问题的解决
609 0
|
应用服务中间件
The Tomcat connector configured to listen on port 10000 failed to start. The port may already be in
The Tomcat connector configured to listen on port 10000 failed to start. The port may already be in
|
Arthas 负载均衡 网络协议
Tomcat连接之KeepAlive逻辑分析
Tomcat连接之KeepAlive逻辑分析
465 1