配置嵌入式Servlet容器

定制和修改Servlet容器的server相关配置

  1. 修改和server有关的配置

    server.port=8081
    server.context-path=/crud
    
    server.tomcat.uri-encoding=UTF-8
    
    //通用的Servlet容器设置
    server.xxx
    //Tomcat的设置
    server.tomcat.xxx
    
  2. 编写一个EmbeddedServletContainerCustomizer,2.0以后改为WebServerFactoryCustomizer:嵌入式的Servlet容器的定制器;来修改Servlet容器的配置,代码方式的配置会覆盖配置文件的配置(和其他Customizer一起代理生成)

    @Configuration
    public class MyMvcConfig implements WebMvcConfigurer {
        @Bean
        public WebServerFactoryCustomizer webServerFactoryCustomizer() {
            return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
                @Override
                public void customize(ConfigurableWebServerFactory factory) {
                    factory.setPort(8088);
                }
            };
        }
    ......
    

修改server配置原理

ServletWebServerFactoryAutoConfiguration在向容器中添加web容器时还添加了一个组件

==

配置嵌入式Servlet容器

BeanPostProcessorsRegistrar:后置处理器注册器(实现了BeanPostProcessor,动态代理后后置处理生成一些Bean)

    public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
        private ConfigurableListableBeanFactory beanFactory;

        public BeanPostProcessorsRegistrar() {...}

        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {...}

        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (this.beanFactory != null) {
                //注册了下面的组件
              registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
					WebServerFactoryCustomizerBeanPostProcessor.class);
            }
        }

        private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {...}
    }



public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

    ......

    //在Bean初始化之前
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //判断添加的Bean是不是WebServerFactory类型的
        if (bean instanceof WebServerFactory) {
            this.postProcessBeforeInitialization((WebServerFactory)bean);
        }

        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
        //获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
        ((Callbacks)LambdaSafe.callbacks(WebServerFactoryCustomizer.class, this.getCustomizers(), webServerFactory, new Object[0]).withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)).invoke((customizer) -> {
            customizer.customize(webServerFactory);
        });
    }

1. BeanPostProcessor简介

BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。接口声明如下:

public interface BeanPostProcessor {
 //bean初始化方法调用前被调用
 Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
 //bean初始化方法调用后被调用
 Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

运行顺序

Spring IOC容器实例化Bean
调用BeanPostProcessor的postProcessBeforeInitialization方法
调用bean实例的初始化方法
调用BeanPostProcessor的postProcessAfterInitialization方法

配置嵌入式Servlet容器

image.png

2. BeanPostProcessor实例

/**
 * 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
        return bean;
    }

}

3. BeanFactoryPostProcessor简介

bean工厂的bean属性处理容器,说通俗一些就是可以管理我们的bean工厂内所有的beandefinition(未实例化)数据,可以随心所欲的修改属性。

4. BeanFactoryPostProcessor实例

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor...postProcessBeanFactory...");
        int count = beanFactory.getBeanDefinitionCount();
        String[] names = beanFactory.getBeanDefinitionNames();
        System.out.println("当前BeanFactory中有"+count+" 个Bean");
        System.out.println(Arrays.asList(names));
    }

}

区别:

注册BeanFactoryPostProcessor的实例,需要重载

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

通过beanFactory可以获取bean的示例或定义等。同时可以修改bean的属性,这是和BeanPostProcessor最大的区别。

关于如何AutoConfiguration中Customizer配置文件是如何设置的,参考EmbeddedWebServerFactoryCustomizerAutoConfiguration类,最后若是常用设置,还是使用propertis配置更为方便。

@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {

	/**
	 * Nested configuration if Tomcat is being used.
	 */
	@Configuration(proxyBeanMethods = false)
    // 若嵌入式Servlet容器导入的为Tomcat的依赖
	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })
	public static class TomcatWebServerFactoryCustomizerConfiguration {

		@Bean
		public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment,
				ServerProperties serverProperties) {
			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
		}
}

该类也实现了WebServerFactoryCustomizer,只是customize方法调用的参数配置不一样,最终都由BeanPostProcessorsRegistrar在创建容器前动态代理与其他WebServerFactoryCustomizer互补配置生成代理类。

public class TomcatWebServerFactoryCustomizer
		implements WebServerFactoryCustomizer,<ConfigurableTomcatWebServerFactory>, Ordered {

	private final Environment environment;

	private final ServerProperties serverProperties;

	public TomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
		this.environment = environment;
		this.serverProperties = serverProperties;
	}
    @Override
	public void customize(ConfigurableTomcatWebServerFactory factory) {
        ·····
    }
}

总结:

  1. SpringBoot根据导入的依赖情况,给容器中添加相应的XXXServletWebServerFactory

  2. 容器中某个组件要创建对象就会惊动后置处理器 webServerFactoryCustomizerBeanPostProcessor

    只要是嵌入式的是Servlet容器工厂,后置处理器就会工作;

  3. 后置处理器,从容器中获取所有的WebServerFactoryCustomizer,调用定制器的定制方法给工厂添加配置

替换为其他嵌入式web容器

如果要换成其他的就把Tomcat的依赖排除掉,然后引入其他嵌入式Servlet容器的以来,如JettyUndertow

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <artifactId>spring-boot-starter-jetty</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <artifactId>spring-boot-starter-undertow</artifactId>
            <groupId>org.springframework.boot</groupId>
        </dependency>

替换原理

查看web容器自动配置类

  1. ServletWebServerFactoryAutoConfiguration在当是服务端的情况下必然启动的配置,在其中完成2版本之前的AnnotationConfigEmbeddedApplicationContext的Embedded判断
  2. xxxWebServerFactoryCustomizer嵌入式web服务器对于自己serverproperties的servler参数的详细设置。
  3. @ImportServletWebServerFactoryConfiguration.EmbeddedTomcat.class时会判断是否符合条件,他将读取EmbeddedWebServerFactoryCustomizerAutoConfiguration中的TomcatWebServerFactoryCustomizer和自己配置的WebServerFactoryCustomizer来生成factory
  4. 若是不是内嵌的servlet,则将下面的两个生效在外部的servlet上(可能)(可能在servletContext上区分除了外部和内嵌)
  5. ServletWebServerFactoryCustomizer读取了配置文件的基本配置,对应于所有内嵌容器中中的server.xml+web.xml中的通用部分提取。
  6. TomcatServletWebServerFactoryCustomizer定制的若是tomcat服务器,则进行一些server中对于servlet的特殊参数的设置

2.0以下是:EmbeddedServletContainerAutoConfiguration

ServletWebServerFactoryAutoConfiguration:嵌入式的web服务器自动配置

@Configuration(
    proxyBeanMethods = false
)
@AutoConfigureOrder(-2147483648)
@ConditionalOnClass({ServletRequest.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@EnableConfigurationProperties({ServerProperties.class})

//---看这里---
@Import({ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, 							ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class})
public class ServletWebServerFactoryAutoConfiguration {
    ···
}

ServletWebServerFactoryConfiguration.EmbeddedTomcat.class

@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {

	@Configuration(proxyBeanMethods = false)
        //判断当前是否引入了Tomcat依赖;
	@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
    	/**
      *判断当前容器没有用户自己定义ServletWebServerFactory:嵌入式的web服务器工厂;
      *作用:创建嵌入式的web服务器
      */
	@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;
		}

	}

我们可以实现ServletWebServerFactory接口来自定义ServletWebServerFactory,它默认为我们实现了常用的服务器。

TomcatServletWebServerFactory为例,接口只要求实现一个便是,getWebServer方法,下面是TomcatServletWebServerFactory类

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

        //创建一个Tomcat
        Tomcat tomcat = new Tomcat();

        //配置Tomcat的基本环境,(tomcat的配置都是从本类获取的,tomcat.setXXX)
        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);

        //将配置好的Tomcat传入进去,返回一个WebServer;并且启动Tomcat服务器
        return this.getTomcatWebServer(tomcat);
    }
  • 依据不同的服务器类型选择,生成不同的服务器,用多个WebServerFactoryCustomizer最后代理生成的TomcatServletWebServerFactory(由修改配置原理的2和3配置互补生成同一种类型的factory)
  • 可以自己自定义或内嵌的生成相应的xxxServletebServerFactory。

内置Servlet的启动原理

内置与外置的差别在于createApplicationContext()的的结果不同,

  1. SpringApplication.run
  2. SpringBoot应用启动运行run方法
public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting();
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
       
      // 若是默认配置且为web应用怎会调用AnnotationConfigServletWebServerApplicationContext,1.5的版本仍是需要AnnotationConfigEmbeddedApplicationContext
      context = createApplicationContext();
       /*try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
	 */
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      //最终会调用相应的applicationContext的refresh()方法;
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      listeners.started(context);
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, null);
      throw new IllegalStateException(ex);
   }
   return context;
}
  1. 查看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;
		}
	}
  1. 调用其父类的refresh方法,其中try中对于bean对象的刷新全都在ServletWebServerApplicationContext中重写了,这里提供一个规范与注释,易于维护与理解,
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 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);

         // Invoke factory processors registered as beans in the context.
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         registerBeanPostProcessors(beanFactory);

         // 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();
      }
   }
}
  1. 对于servlet的启动,重要的是onRefresh()方法
@Override
protected void onRefresh() {
    //调用父类的onRefresh,输出了时间戳
   super.onRefresh();
   try {
       //创建服务器服务
      createWebServer();
   }
   catch (Throwable ex) {
      throw new ApplicationContextException("Unable to start web server", ex);
   }
}

7.createWebServer();

private void createWebServer() {
   WebServer webServer = this.webServer;
   ServletContext servletContext = getServletContext();
   if (webServer == null && servletContext == null) {//可能在这里区分出了外部和内嵌的区别
       
       //获取当前系统由配置类自动生成到容器中的factory
      ServletWebServerFactory factory = getWebServerFactory();
       //用该factory生成一个对应类型的服务器,并在xxxWebServer的初始化时会启动xxx服务器。
       // 其中xxxServletWebServerFactory(若是tomcat)则会new tomcat和StandardServer等Tomcat外置服务器中同样 org.apache.catalina包中的类,之后和tomcat一样的启动流程。
      this.webServer = factory.getWebServer(getSelfInitializer());
      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();
}
  • 若获取的是tomcat服务器,则配置后启动
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
   if (this.disableMBeanRegistry) {
      Registry.disableRegistry();
   }
   // 给将配置的参数放置在tomcat类中以便初始化何启动
   // tomcat也为org.apache.catalina.startup包中的类,用于内嵌式时自己启动,自己配置server,service等组件,不同于用批处理命令开启读取xml文件创建server的方式
   Tomcat tomcat = new Tomcat();
   File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
   tomcat.setBaseDir(baseDir.getAbsolutePath());
   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);
    //获取TomcatWebServer,设置启动级别,初始化若是1则同时启动
   return getTomcatWebServer(tomcat);
}
  1. 嵌入式的Servlet容器创建对象并启动Servlet容器;

  2. 嵌入式的Servlet容器启动后,再将ioc容器中剩下没有创建出的对象获取出来(Controller,Service等);

使用外置的Servlet容器

  1. 将项目的打包方式改为war

  2. 编写一个类继承SpringBootServletInitializer,并重写configure方法,调用参数的sources方法springboot启动类传过去然后返回

    public class ServletInitializer extends SpringBootServletInitializer {
        @Override
        protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
            return application.sources(HelloSpringBootWebApplication.class);
        }
    }
    
  3. 然后把tomcat的依赖范围改为provided

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
                <version>2.2.1.RELEASE</version>
                <scope>provided</scope>
            </dependency>
    
            ......
    
        </dependencies>
    
  4. 最后就可以把项目打包成war放到tomcat中了

  5. 在IDEA中可以这样配置

    配置嵌入式Servlet容器

  6. 在创建项目时使用Spring Initializr创建选择打包方式为war,1,2,3步骤会自动配置

使用外置Servlet的原理

TODO 2019-11-20

  1. Servlet3.0标准ServletContainerInitializer扫描所有jar包中METAINF/services/javax.servlet.ServletContainerInitializer文件指定的类并加载

  2. 还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类;

  3. 在spring-web-xxx.jar包中的METAINF/services下有javax.servlet.ServletContainerInitializer这个文件

    文件中的类是:

    org.springframework.web.SpringServletContainerInitializer
    

    对应的类:

    @HandlesTypes({WebApplicationInitializer.class})
    public class SpringServletContainerInitializer implements ServletContainerInitializer {
        public SpringServletContainerInitializer() {
        }
    
        public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
    
            ......
    
  4. SpringServletContainerInitializer将@HandlesTypes(WebApplicationInitializer.class)标注的所有这个类型的类都传入到onStartup方法的Set<Class<?>>;为这些WebApplicationInitializer类型的类创建实例;

  5. 每一个WebApplicationInitializer都调用自己的onStartup方法;

  6. WebApplicationInitializer的实现类

配置嵌入式Servlet容器

  1. 相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法

  2. SpringBootServletInitializer实例执行onStartup的时候会createRootApplicationContext;创建容器

    protected WebApplicationContext createRootApplicationContext(
          ServletContext servletContext) {
        //1、创建SpringApplicationBuilder
       SpringApplicationBuilder builder = createSpringApplicationBuilder();
       StandardServletEnvironment environment = new StandardServletEnvironment();
       environment.initPropertySources(servletContext, null);
       builder.environment(environment);
       builder.main(getClass());
       ApplicationContext parent = getExistingRootWebApplicationContext(servletContext);
       if (parent != null) {
          this.logger.info("Root context already created (using as parent).");
          servletContext.setAttribute(
                WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, null);
          builder.initializers(new ParentContextApplicationContextInitializer(parent));
       }
       builder.initializers(
             new ServletContextApplicationContextInitializer(servletContext));
       builder.contextClass(AnnotationConfigEmbeddedWebApplicationContext.class);
    
        //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入了进来
       builder = configure(builder);
    
        //使用builder创建一个Spring应用
       SpringApplication application = builder.build();
       if (application.getSources().isEmpty() && AnnotationUtils
             .findAnnotation(getClass(), Configuration.class) != null) {
          application.getSources().add(getClass());
       }
       Assert.state(!application.getSources().isEmpty(),
             "No SpringApplication sources have been defined. Either override the "
                   + "configure method or add an @Configuration annotation");
       // Ensure error pages are registered
       if (this.registerErrorPageFilter) {
          application.getSources().add(ErrorPageFilterConfiguration.class);
       }
        //启动Spring应用
       return run(application);
    }
    
  3. Spring的应用就启动并且创建IOC容器

    public ConfigurableApplicationContext run(String... args) {
       StopWatch stopWatch = new StopWatch();
       stopWatch.start();
       ConfigurableApplicationContext context = null;
       FailureAnalyzers analyzers = null;
       configureHeadlessProperty();
       SpringApplicationRunListeners listeners = getRunListeners(args);
       listeners.starting();
       try {
          ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
          ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
          Banner printedBanner = printBanner(environment);
         // 若是web应用则调用AnnotationConfigServletWebServerApplicationContext,1.5的版本仍是需要AnnotationConfigEmbeddedApplicationContext
          context = createApplicationContext();
          analyzers = new FailureAnalyzers(context);
          prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
    
           //刷新IOC容器
          refreshContext(context);
          afterRefresh(context, applicationArguments);
          listeners.finished(context, null);
          stopWatch.stop();
          if (this.logStartupInfo) {
             new StartupInfoLogger(this.mainApplicationClass)
                   .logStarted(getApplicationLog(), stopWatch);
          }
          return context;
       }
       catch (Throwable ex) {
          handleRunFailure(context, listeners, analyzers, ex);
          throw new IllegalStateException(ex);
       }
    }