码迷,mamicode.com
首页 > 编程语言 > 详细

SpringBoot内嵌Tomcat启动原理

时间:2021-04-01 13:27:41      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:pwa   env   gre   process   tee   ref   argument   ota   rar   

SpringBoot应用启动运行run方法,然后一直来到这个Run方法
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
    this.configureHeadlessProperty();
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();


    Collection exceptionReporters;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        this.configureIgnoreBeanInfo(environment);
        Banner printedBanner = this.printBanner(environment);
        context = this.createApplicationContext();//创建Springboot应用程序(即ApplicationContext),根据环境创建的
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        this.refreshContext(context);//刷新IOC容器,即创建IOC容器对象,并初始化容器,创建容器中的每一个组件(即Bean)
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        try {
            switch(this.webApplicationType) {
            case SERVLET:
//如果是Srevlet环境就创建Servlet的SpringBoot应用
                contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                break;
            case REACTIVE:
                contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                break;
            default:
                contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
            }
        } catch (ClassNotFoundException var3) {
            throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
        }
    }




    return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}

public void refresh() throws BeansException, IllegalStateException {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);


        try {
            this.postProcessBeanFactory(beanFactory);
            this.invokeBeanFactoryPostProcessors(beanFactory);
            this.registerBeanPostProcessors(beanFactory);
            this.initMessageSource();
            this.initApplicationEventMulticaster();
            this.onRefresh();//web的ioc容器重写了onRefresh方法
            this.registerListeners();
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();

protected void onRefresh() {
    super.onRefresh();


    try {
        this.createWebServer();//创建嵌入式的Servlet容器,不过是先获取容器工厂,再创建容器
    } catch (Throwable var2) {
        throw new ApplicationContextException("Unable to start web server", var2);
    }
}

private void createWebServer() {
    WebServer webServer = this.webServer;
    ServletContext servletContext = this.getServletContext();
    if (webServer == null && servletContext == null) {
        ServletWebServerFactory factory = this.getWebServerFactory();//先获取工厂
从ioc容器中获取TomcatServletWebServerFactory 组件(是一个bean来的)
         通过这个TomcatServletWebServerFactory创建Tomcat对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;
        this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});//再获取容器
    } else if (servletContext != null) {
        try {
            this.getSelfInitializer().onStartup(servletContext);
        } catch (ServletException var4) {
            throw new ApplicationContextException("Cannot initialize servlet context", var4);
        }
    }


    this.initPropertySources();
}

public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
        Registry.disableRegistry();
    }


    Tomcat tomcat = new Tomcat();
    File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol);
    connector.setThrowOnFailure(true);
    tomcat.getService().addConnector(connector);
    this.customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    this.configureEngine(tomcat.getEngine());
    Iterator var5 = this.additionalTomcatConnectors.iterator();


    while(var5.hasNext()) {
        Connector additionalConnector = (Connector)var5.next();
        tomcat.getService().addConnector(additionalConnector);
    }


    this.prepareContext(tomcat.getHost(), initializers);
    return this.getTomcatWebServer(tomcat);
}

protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
    return new TomcatWebServer(tomcat, this.getPort() >= 0);//端口号大于0就自动启动
}

public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
    this.monitor = new Object();
    this.serviceConnectors = new HashMap();
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    this.initialize();//启动
}
嵌入式的Servlet容器创建对象并启动Servlet容器;


TomcatServletWebServerFactory是在ServletWebServerFactoryConfiguration被加入进容器的
注入之后在ServletWebServerFactoryAutoConfiguration被导入
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,//导入这个class对象
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })

第二步
@Configuration(proxyBeanMethods = false)
//判断是否导入了Tomcat依赖,导入了就把TomcatServletWebServerFactory放入ioc容器
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
   @Bean
   TomcatServletWebServerFactory tomcatServletWebServerFactory(
         ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
         ObjectProvider<TomcatContextCustomizer> contextCustomizers,
         ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
      TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
      factory.getTomcatConnectorCustomizers()
            .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
      factory.getTomcatContextCustomizers()
            .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
      factory.getTomcatProtocolHandlerCustomizers()
            .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
      return factory;
   }
}


第三步
public WebServer getWebServer(ServletContextInitializer... initializers) {
    if (this.disableMBeanRegistry) {
        Registry.disableRegistry();
    }


    Tomcat tomcat = new Tomcat();//获取Tomcat
    //配置Tomcat基本环节
    File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
    tomcat.setBaseDir(baseDir.getAbsolutePath());
    Connector connector = new Connector(this.protocol);
    connector.setThrowOnFailure(true);
    tomcat.getService().addConnector(connector);
    this.customizeConnector(connector);
    tomcat.setConnector(connector);
    tomcat.getHost().setAutoDeploy(false);
    this.configureEngine(tomcat.getEngine());
    Iterator var5 = this.additionalTomcatConnectors.iterator();


    while(var5.hasNext()) {
        Connector additionalConnector = (Connector)var5.next();
        tomcat.getService().addConnector(additionalConnector);
    }


    this.prepareContext(tomcat.getHost(), initializers);
    return this.getTomcatWebServer(tomcat);//开始启动Tomcat
}

第四步
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
    return new TomcatWebServer(tomcat, this.getPort() >= 0);//端口大于0就自动启动
}

第五步
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
    this.monitor = new Object();
    this.serviceConnectors = new HashMap();
    Assert.notNull(tomcat, "Tomcat Server must not be null");
    this.tomcat = tomcat;
    this.autoStart = autoStart;
    this.initialize();//准备启动
}

第六步
private void initialize() throws WebServerException {
    logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
    Object var1 = this.monitor;
    synchronized(this.monitor) {
        try {
            this.addInstanceIdToEngineName();
            Context context = this.findContext();
            context.addLifecycleListener((event) -> {
                if (context.equals(event.getSource()) && "start".equals(event.getType())) {
                    this.removeServiceConnectors();
                }


            });
            this.tomcat.start();//启动tomcat
        
}



@Bean
//如果classpath有Tomcat就把TomcatServletWebServerFactoryCustomizer放入容器
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
      ServerProperties serverProperties) {
   return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}

 

SpringBoot内嵌Tomcat启动原理

标签:pwa   env   gre   process   tee   ref   argument   ota   rar   

原文地址:https://www.cnblogs.com/hanabivvv/p/14604182.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!