咱们晓得,springBoot我的项目只需运行main函数即可,那么tomcat是怎么启动的,springmvc又是如何和tomcat绑定的呢?

1.如何启动tomcat

从SpringBoot主类run办法进入,看context = createApplicationContext();

    /**     * Run the Spring application, creating and refreshing a new     * {@link ApplicationContext}.     * @param args the application arguments (usually passed from a Java main method)     * @return a running {@link ApplicationContext}     */    public ConfigurableApplicationContext run(String... args) {        long startTime = System.nanoTime();        DefaultBootstrapContext bootstrapContext = createBootstrapContext();        ConfigurableApplicationContext context = null;        configureHeadlessProperty();        SpringApplicationRunListeners listeners = getRunListeners(args);        listeners.starting(bootstrapContext, this.mainApplicationClass);        try {            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);            configureIgnoreBeanInfo(environment);            Banner printedBanner = printBanner(environment);            //创立web环境            context = createApplicationContext();            context.setApplicationStartup(this.applicationStartup);            prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);            refreshContext(context);            afterRefresh(context, applicationArguments);            Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);            if (this.logStartupInfo) {                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);            }            listeners.started(context, timeTakenToStartup);            callRunners(context, applicationArguments);        }        catch (Throwable ex) {            handleRunFailure(context, ex, listeners);            throw new IllegalStateException(ex);        }        try {            Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);            listeners.ready(context, timeTakenToReady);        }        catch (Throwable ex) {            handleRunFailure(context, ex, null);            throw new IllegalStateException(ex);        }        return context;    }    /**     * Strategy method used to create the {@link ApplicationContext}. By default this     * method will respect any explicitly set application context class or factory before     * falling back to a suitable default.     * @return the application context (not yet refreshed)     * @see #setApplicationContextFactory(ApplicationContextFactory)     */    protected ConfigurableApplicationContext createApplicationContext() {        return this.applicationContextFactory.create(this.webApplicationType);    }    private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;@FunctionalInterfacepublic interface ApplicationContextFactory {    /**     * A default {@link ApplicationContextFactory} implementation that will create an     * appropriate context for the {@link WebApplicationType}.     */    ApplicationContextFactory DEFAULT = (webApplicationType) -> {        try {            // 从spring.factories中获取ApplicationFactory的实现类            for (ApplicationContextFactory candidate : SpringFactoriesLoader                    .loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {             //获取到AnnotationConfigServletWebServerApplicationContext对象                ConfiguraAnnotationConfigServletWebServerApplicationContext对象bleApplicationContext context = candidate.create(webApplicationType);                if (context != null) {                    return context;                }            }            return new AnnotationConfigApplicationContext();        }        catch (Exception ex) {            throw new IllegalStateException("Unable create a default ApplicationContext instance, "                    + "you may need a custom ApplicationContextFactory", ex);        }    };

能够看到ApplicationContextFactory是一个函数式接口,那么applicationContextFactory.create的时候会调用lambda表达式,lamdba表达式里从spring.factories中获取ApplicationFactory的实现类,那么candidate.create(webApplicationType)只能获取到AnnotationConfigServletWebServerApplicationContext

再回到后面,看refreshContext(context)->refresh(context)->applicationContext.refresh();;
AnnotationConfigServletWebServerApplicationContext没有refresh办法,调用的是父类ServletWebServerApplicationContext的refresh办法:

    @Override    public final void refresh() throws BeansException, IllegalStateException {        try {            super.refresh();        }        catch (RuntimeException ex) {            WebServer webServer = this.webServer;            if (webServer != null) {                webServer.stop();            }            throw ex;        }    }

ServletWebServerApplicationContext调用的也是父类AbstractApplicationContext的refresh办法:

    @Override    public void refresh() throws BeansException, IllegalStateException {        synchronized (this.startupShutdownMonitor) {            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");            // Prepare this context for refreshing.            prepareRefresh();            // Tell the subclass to refresh the internal bean factory.            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            // Prepare the bean factory for use in this context.            prepareBeanFactory(beanFactory);            try {                // Allows post-processing of the bean factory in context subclasses.                postProcessBeanFactory(beanFactory);                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");                // Invoke factory processors registered as beans in the context.                invokeBeanFactoryPostProcessors(beanFactory);                // Register bean processors that intercept bean creation.                registerBeanPostProcessors(beanFactory);                beanPostProcess.end();                // Initialize message source for this context.                initMessageSource();                // Initialize event multicaster for this context.                initApplicationEventMulticaster();                // Initialize other special beans in specific context subclasses.                onRefresh();                // Check for listener beans and register them.                registerListeners();                // Instantiate all remaining (non-lazy-init) singletons.                finishBeanFactoryInitialization(beanFactory);                // Last step: publish corresponding event.                finishRefresh();            }            catch (BeansException ex) {                if (logger.isWarnEnabled()) {                    logger.warn("Exception encountered during context initialization - " +                            "cancelling refresh attempt: " + ex);                }                // Destroy already created singletons to avoid dangling resources.                destroyBeans();                // Reset 'active' flag.                cancelRefresh(ex);                // Propagate exception to caller.                throw ex;            }            finally {                // Reset common introspection caches in Spring's core, since we                // might not ever need metadata for singleton beans anymore...                resetCommonCaches();                contextRefresh.end();            }        }    }

看onRefresh()办法:

    /**     * Template method which can be overridden to add context-specific refresh work.     * Called on initialization of special beans, before instantiation of singletons.     * <p>This implementation is empty.     * @throws BeansException in case of errors     * @see #refresh()     */    protected void onRefresh() throws BeansException {        // For subclasses: do nothing by default.    }

空办法,交由子类实现,也就是ServletWebServerApplicationContext:

    @Override    protected void onRefresh() {      //父类办法初始化了web我的项目的ui主题        super.onRefresh();        try {        //创立web容器            createWebServer();        }        catch (Throwable ex) {            throw new ApplicationContextException("Unable to start web server", ex);        }    }    private void createWebServer() {        WebServer webServer = this.webServer;        ServletContext servletContext = getServletContext();        //进入这里        if (webServer == null && servletContext == null) {        //创立一个DefaultStartupStep            StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");            //获取TomcatServletWebServerFactory            ServletWebServerFactory factory = getWebServerFactory();            createWebServer.tag("factory", factory.getClass().toString());            //获取TomcatWebServer            this.webServer = factory.getWebServer(getSelfInitializer());            createWebServer.end();            getBeanFactory().registerSingleton("webServerGracefulShutdown",                    new WebServerGracefulShutdownLifecycle(this.webServer));            getBeanFactory().registerSingleton("webServerStartStop",                    new WebServerStartStopLifecycle(this, this.webServer));        }        else if (servletContext != null) {            try {                getSelfInitializer().onStartup(servletContext);            }            catch (ServletException ex) {                throw new ApplicationContextException("Cannot initialize servlet context", ex);            }        }        initPropertySources();    }

首先看getWebServerFactory是如何获取TomcatServletWebServerFactory的:

    /**     * Returns the {@link ServletWebServerFactory} that should be used to create the     * embedded {@link WebServer}. By default this method searches for a suitable bean in     * the context itself.     * @return a {@link ServletWebServerFactory} (never {@code null})     */    protected ServletWebServerFactory getWebServerFactory() {        // Use bean names so that we don't consider the hierarchy   //从beanFactory获取ServletWebServerFactory的名称        String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);//只能有一个        if (beanNames.length == 0) {            throw new MissingWebServerFactoryBeanException(getClass(), ServletWebServerFactory.class,                    WebApplicationType.SERVLET);        }        if (beanNames.length > 1) {            throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple "                    + "ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));        }//获取该beanFactory        return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);    }

能够看到ServletWebServerFactory的实现类有很多个,springBoot默认的实现是TomcatServletWebServerFactory,

它是什么时候退出bean工厂的呢?通过搜寻得悉它是在ServletWebServerFactoryConfiguration中被注册的:

咱们再看this.webServer = factory.getWebServer(getSelfInitializer());

    @Override    public WebServer getWebServer(ServletContextInitializer... initializers) {        if (this.disableMBeanRegistry) {            Registry.disableRegistry();        }        Tomcat tomcat = new Tomcat();        File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");        tomcat.setBaseDir(baseDir.getAbsolutePath());        for (LifecycleListener listener : this.serverLifecycleListeners) {            tomcat.getServer().addLifecycleListener(listener);        }        Connector connector = new Connector(this.protocol);        connector.setThrowOnFailure(true);        tomcat.getService().addConnector(connector);        customizeConnector(connector);        tomcat.setConnector(connector);        tomcat.getHost().setAutoDeploy(false);        configureEngine(tomcat.getEngine());        for (Connector additionalConnector : this.additionalTomcatConnectors) {            tomcat.getService().addConnector(additionalConnector);        }        prepareContext(tomcat.getHost(), initializers);        return getTomcatWebServer(tomcat);    }    /**     * Factory method called to create the {@link TomcatWebServer}. Subclasses can     * override this method to return a different {@link TomcatWebServer} or apply     * additional processing to the Tomcat server.     * @param tomcat the Tomcat server.     * @return a new {@link TomcatWebServer} instance     */    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {        return new TomcatWebServer(tomcat, getPort() >= 0);    }    /**     * Create a new {@link TomcatWebServer} instance.     * @param tomcat the underlying Tomcat server     * @param autoStart if the server should be started     */    public TomcatWebServer(Tomcat tomcat, boolean autoStart) {        Assert.notNull(tomcat, "Tomcat Server must not be null");        this.tomcat = tomcat;        this.autoStart = autoStart;        initialize();    }    private void initialize() throws WebServerException {        logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));        synchronized (this.monitor) {            try {                addInstanceIdToEngineName();                Context context = findContext();                context.addLifecycleListener((event) -> {                    if (context.equals(event.getSource())                            && Lifecycle.START_EVENT.equals(event.getType())) {                        // Remove service connectors so that protocol binding doesn't                        // happen when the service is started.                        removeServiceConnectors();                    }                });                // Start the server to trigger initialization listeners                // 启动tomcat                this.tomcat.start();                // We can re-throw failure exception directly in the main thread                rethrowDeferredStartupExceptions();                try {                    ContextBindings.bindClassLoader(context, context.getNamingToken(),                            getClass().getClassLoader());                }                catch (NamingException ex) {                    // Naming is not enabled. Continue                }                // Unlike Jetty, all Tomcat threads are daemon threads. We create a                // blocking non-daemon to stop immediate shutdown                startDaemonAwaitThread();            }            catch (Exception ex) {                stopSilently();                throw new WebServerException("Unable to start embedded Tomcat", ex);            }        }    }

初始化了一个tomcat并启动。

2.tomcat如何注册DispatchServlet

回到this.webServer = factory.getWebServer(getSelfInitializer());
这行代码,看getSelfInitializer();

    /**     * Returns the {@link ServletContextInitializer} that will be used to complete the     * setup of this {@link WebApplicationContext}.     * @return the self initializer     * @see #prepareWebApplicationContext(ServletContext)     */    private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {        return this::selfInitialize;    }    private void selfInitialize(ServletContext servletContext) throws ServletException {        prepareWebApplicationContext(servletContext);        ConfigurableListableBeanFactory beanFactory = getBeanFactory();        ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(                beanFactory);        WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,                getServletContext());        existingScopes.restore();        WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,                getServletContext());        // 获取ServletContextInitializer实现类        for (ServletContextInitializer beans : getServletContextInitializerBeans()) {// 注册dispatchServlet            beans.onStartup(servletContext);        }    }    @SafeVarargs    public ServletContextInitializerBeans(ListableBeanFactory beanFactory,            Class<? extends ServletContextInitializer>... initializerTypes) {        this.initializers = new LinkedMultiValueMap<>();        this.initializerTypes = (initializerTypes.length != 0)                ? Arrays.asList(initializerTypes)                : Collections.singletonList(ServletContextInitializer.class);        // 这里实例化了dispatchServlet        addServletContextInitializerBeans(beanFactory);        addAdaptableBeans(beanFactory);        List<ServletContextInitializer> sortedInitializers = this.initializers.values()                .stream()                .flatMap((value) -> value.stream()                        .sorted(AnnotationAwareOrderComparator.INSTANCE))                .collect(Collectors.toList());        this.sortedList = Collections.unmodifiableList(sortedInitializers);    }    private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {// 实例化ServletContextInitializer的实现类        for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(                beanFactory, ServletContextInitializer.class)) {            addServletContextInitializerBean(initializerBean.getKey(),                    initializerBean.getValue(), beanFactory);        }    }

ServletContextInitializer的实现类中有个dispatcherServletRegistration,就是讲dispatchServlet注册到tomcat的;
再回到initializer.onStartup办法:

@Override    public void onStartup(Set<Class<?>> classes, ServletContext servletContext)            throws ServletException {        try {            for (ServletContextInitializer initializer : this.initializers) {              //注册dispatchServlet                initializer.onStartup(servletContext);            }        }        catch (Exception ex) {            this.startUpException = ex;            // Prevent Tomcat from logging and re-throwing when we know we can            // deal with it in the main thread, but log for information here.            if (logger.isErrorEnabled()) {                logger.error("Error starting Tomcat context. Exception: "                        + ex.getClass().getName() + ". Message: " + ex.getMessage());            }        }    }

这里的initializer就是dispatcherServletRegistration,然而他没有onStartup办法,它调用的是它的父类RegistrationBean这个实现类:

    @Override    public final void onStartup(ServletContext servletContext) throws ServletException {        String description = getDescription();        if (!isEnabled()) {            logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");            return;        }         //注册        register(description, servletContext);    }

由子类DynamicRegistrationBean实现:

    @Override    protected final void register(String description, ServletContext servletContext) {           //注册        D registration = addRegistration(description, servletContext);        if (registration == null) {            logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");            return;        }        configure(registration);    }

addRegistration由子类ServletRegistrationBean实现:

能够看到,这里将dispatchServlet注册进了tomcat的servlet。