SpringBoot启动流程:

调用SpringApplication.run启动springboot应用

public static void main(String[] args) {
    SpringApplication.run(ServiceApplication.class, args);
}

使用自定义SpringApplication进行启动

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   return new SpringApplication(primarySources).run(args);
}

1. new SpringApplication()

new SpringApplication(primarySources)

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  //此时为null,可以通过此参数指定类加载器
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   // 将启动类放入primarySources 
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   //推断是什么web应用类型,reactive,servlet
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   // 就是去spring.factories 中去获取所有key:org.springframework.context.ApplicationContextInitializer
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   //就是去spring.factories 中去获取所有key: org.springframework.context.ApplicationListener
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   // 根据main方法推算出mainApplicationClass 
   this.mainApplicationClass = deduceMainApplicationClass();
}

getSpringFactoriesInstances(ApplicationListener.class)

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

//通过getClassLoader 从META-INF/spring.factories获取指定的Spring的工厂实例
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    //默认为Thread.currentThread().getContextClassLoader()/ClassLoader.getSystemClassLoader()
    ClassLoader classLoader = getClassLoader();
    //读取 key 为 type.getName() 的 value
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    //反射创建Bean
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

可以自定义事件监听器和初始化干预

createSpringFactoriesInstances
private <T> List<T> createSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, ClassLoader                                 classLoader, Object[] args,Set<String> names) {
    List<T> instances = new ArrayList<>(names.size());
    for (String name : names) {
        try {
            //装载class文件到内存
            Class<?> instanceClass = ClassUtils.forName(name, classLoader);
            Assert.isAssignable(type, instanceClass);
            Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
            //通过反射创建实例
            T instance = (T) BeanUtils.instantiateClass(constructor, args);
            instances.add(instance);
        } catch (Throwable ex) {
            throw new IllegalArgumentException(
                "Cannot instantiate " + type + " : " + name, ex);
        }
    }
    return instances;
}

总结一下,new SpringApplication(primarySources)就是将main方法的SpringApplication.run(ServiceApplication.class, args)的class对象利用反射来实例化,并组装成SpringApplication对象

2. run()

启动springboot最核心的逻辑

public ConfigurableApplicationContext run(String... args) {
    // 用来记录当前springboot启动耗时
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   // 它是任何spring上下文的接口, 所以可以接收任何ApplicationContext实现
   ConfigurableApplicationContext context = null;
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
   // 开启了Headless模式:
   //headless是J2SE的一种模式,用于在缺少显示屏、键盘或者鼠标时的系统配置,很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true
   configureHeadlessProperty();
   
   //从META-INF/spring.factories中获取监听器  SpringApplicationRunListeners
   SpringApplicationRunListeners listeners = getRunListeners(args);
   
   //遍历回调SpringApplicationRunListeners的starting方法
   listeners.starting();
   
   try {
       //封装命令行参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //构造应用上下文环境,完成后回调SpringApplicationRunListeners的environmentPrepared方法
      ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
      //处理需要忽略的Bean
      configureIgnoreBeanInfo(environment);
      
      // 打印Banner 
      Banner printedBanner = printBanner(environment);
      //根据是否web环境创建相应的IOC容器
      context = createApplicationContext();
      
      //实例化SpringBootExceptionReporter,用来支持报告关于启动的错误
      exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
            new Class[] { ConfigurableApplicationContext.class }, context);
            
      //准备上下文环境,将environment保持到IOC容器中
      //执行applyInitializers,遍历回调ApplicationContextInitializer的initialize方法
      //遍历回调SpringApplicationRunListeners的contextPrepared方法
      //遍历回调SpringApplicationRunListeners的contextLoaded方法
      prepareContext(context, environment, listeners, applicationArguments, printedBanner);
      
      //刷新应用上下文,组件扫描、创建、加载
      //  加载自动配置类:invokeBeanFactoryPostProcessors ,  创建servlet容器onRefresh
      refreshContext(context);
      
      //从IOC容器获取所有的ApplicationRunner(先调用)和CommandLinedRunner进行回调
      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:获取并启动监听器

2:构造容器环境

3:初始化容器,创建容器

4:报告错误信息

5:刷新应用上下文前的准备阶段

6:刷新容器

7:刷新容器后的扩展接口

getRunListeners

加载spring.factories中的配置文件,获取并启动监听器EventPublishingRunListener

private SpringApplicationRunListeners getRunListeners(String[] args) {
   Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
   return new SpringApplicationRunListeners(logger,
         getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
	ClassLoader classLoader = getClassLoader();
	// Use names and ensure unique to protect against duplicates
	Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
	List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
	AnnotationAwareOrderComparator.sort(instances);
	return instances;
}

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
	String factoryTypeName = factoryType.getName();
	return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
		MultiValueMap<String, String> result = cache.get(classLoader);
		if (result != null) {
			return result;
		}

		try {
			Enumeration<URL> urls = (classLoader != null ?
				//这里的FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";就是springboot的自动装配机制
					classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
					ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
			result = new LinkedMultiValueMap<>();
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				UrlResource resource = new UrlResource(url);
				Properties properties = PropertiesLoaderUtils.loadProperties(resource);
				for (Map.Entry<?, ?> entry : properties.entrySet()) {
					String factoryTypeName = ((String) entry.getKey()).trim();
					for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
						result.add(factoryTypeName, factoryImplementationName.trim());
					}
				}
			}
			cache.put(classLoader, result);
			return result;
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Unable to load factories from location [" +
					FACTORIES_RESOURCE_LOCATION + "]", ex);
		}
	}

监听器EventPublishingRunListener

public EventPublishingRunListener(SpringApplication application, String[] args) {
    this.application = application;
    this.args = args;
    this.initialMulticaster = new SimpleApplicationEventMulticaster();
    for (ApplicationListener<?> listener : application.getListeners()) {
        this.initialMulticaster.addApplicationListener(listener);
    }
}

//SimpleApplicationEventMulticaster extends  AbstractApplicationEventMulticaster
public void addApplicationListener(ApplicationListener<?> listener) {
    synchronized (this.retrievalMutex) {
        //避免重复  放入set,去掉代理对象
        Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
        if (singletonTarget instanceof ApplicationListener) {
            this.defaultRetriever.applicationListeners.remove(singletonTarget);
        }
        //内部类对象,保存所有的监听器
        this.defaultRetriever.applicationListeners.add(listener);
        this.retrieverCache.clear();
    }
}

SimpleApplicationEventMulticaster父类AbstractApplicationEventMulticaster中。关键代码为this.defaultRetriever.applicationListeners.add(listener);,这是一个内部类,用来保存所有的ApplicationListener监听器。也就是在这一步,将spring.factories中的监听器传递到SimpleApplicationEventMulticaster中。

listeners.starting();

启动监听器

public void starting() {
    //关键代码,这里是创建application启动事件:ApplicationStartingEvent发布启动事件
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

EventPublishingRunListener这个是springBoot框架中最早执行的监听器,在该监听器执行started()方法时,会继续发布事件,也就是事件传递。这种实现主要还是基于spring的事件机制。继续跟进SimpleApplicationEventMulticaster,有个核心方法:

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    //找出匹配该事件的监听器
    for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        //获取线程池,如果为空则同步处理。这里线程池为空,还未初始化。
        Executor executor = getTaskExecutor();
        if (executor != null) {
            //异步发送事件
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            //同步发送事件
            invokeListener(listener, event);
        }
    }
}
protected Collection<ApplicationListener<?>> getApplicationListeners(
    ....构建缓存
    Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType,                                                                      retriever);
    this.retrieverCache.put(cacheKey, retriever);
    return listeners;
    ...
}
    
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
    ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
    List<ApplicationListener<?>> allListeners = new ArrayList<>();
    Set<ApplicationListener<?>> listeners;
    Set<String> listenerBeans;
    synchronized (this.retrievalMutex) {
        listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
        listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
    }
    //找出适配监听事件的监听器
    for (ApplicationListener<?> listener : listeners) {
        if (supportsEvent(listener, eventType, sourceType)) {
            if (retriever != null) {
                retriever.applicationListeners.add(listener);
            }
            allListeners.add(listener);
        }
    }
    ...

这是springBoot启动过程中,第一处根据类型,执行监听器的地方。根据发布的事件类型从所有监听器中选择对应的监听器进行事件发布

prepareEnvironment

构造容器环境,首先是创建并按照相应的应用类型配置相应的环境,然后根据用户的配置,配置系统环境,然后启动监听器,并加载系统配置文件。

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
      ApplicationArguments applicationArguments) {
   //创建并配置相应的环境,获取对应的ConfigurableEnvironment
   ConfigurableEnvironment environment = getOrCreateEnvironment();
   // 将命令行参数读取到环境变量中
   configureEnvironment(environment, applicationArguments.getSourceArgs());
   // 将@PropertieSource的配置信息 放在第一位, 因为读取配置文件@PropertieSource优先级是最低的
   ConfigurationPropertySources.attach(environment);
   
   //发布监听事件, ConfigFileApplicationListener 就是加载项目配置文件的监听器。
   // 发布了ApplicationEnvironmentPreparedEvent 的监听器  读取了全局配置文件
   listeners.environmentPrepared(environment);
   // 将所有spring.main 开头的配置信息绑定SpringApplication
   bindToSpringApplication(environment);
   if (!this.isCustomEnvironment) {
      environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
            deduceEnvironmentClass());
   }
   //更新PropertySources
   ConfigurationPropertySources.attach(environment);
   return environment;
}

getOrCreateEnvironment()

//根据环境创建对应ConfigurableEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();//Web程序
        case REACTIVE:
            return new StandardReactiveWebEnvironment();//响应式web环境
        default:
            return new StandardEnvironment();//普通程序
    }
}

configureEnvironment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    // 将main 函数的args封装成 SimpleCommandLinePropertySource 加入environment中。
    configurePropertySources(environment, args);
    // 激活相应的配置文件
    configureProfiles(environment, args);
}

listeners.environmentPrepared(environment);

@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
   this.initialMulticaster
         .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
multicastEvent
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   Executor executor = getTaskExecutor();
   //ConfigFileApplicationListener加载配置到environment
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

createApplicationContext

创建容器,如果是servlet项目,容器就是AnnotationConfigServletWebServerApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.applicationContextClass;
    if (contextClass == null) {
        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);
            }
        }catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
             "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
        }
    }
    //利用反射来实例化ApplicationContext
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

//servlet项目容器
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
      + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

prepareContext

刷新容器前的准备阶段,将启动类注入容器,为后续开启自动化配置奠定基础。

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
      SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
      
   //设置容器环境
   context.setEnvironment(environment);
   
   //执行容器后置处理
   postProcessApplicationContext(context);
   
   //执行容器中的 ApplicationContextInitializer 包括spring.factories和通过三种方式自定义的
   applyInitializers(context);
   
    //向各个监听器发送容器已经准备好的事件
   listeners.contextPrepared(context);
   if (this.logStartupInfo) {
      logStartupInfo(context.getParent() == null);
      logStartupProfileInfo(context);
   }
   // 获取当前spring上下文beanFactory (负责创建bean)
   ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
   
   //将main函数中的args参数封装成单例Bean,注册进容器
   beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
   if (printedBanner != null) {
      //将 printedBanner 封装成单例,注册进容器
      beanFactory.registerSingleton("springBootBanner", printedBanner);
   }
   // 在Spring下 如果出现2个重名的bean, 则后读取到的会覆盖前面
   // 在SpringBoot 在这里设置了不允许覆盖, 当出现2个重名的bean 会抛出异常
   if (beanFactory instanceof DefaultListableBeanFactory) {
      ((DefaultListableBeanFactory) beanFactory)
            .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
   }
   // 设置当前spring容器是不是要将所有的bean设置为懒加载
   if (this.lazyInitialization) {
      context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
   }
   // Load the sources
   Set<Object> sources = getAllSources();
   Assert.notEmpty(sources, "Sources must not be empty");
   
   //加载启动类,将启动类注入容器,sources.toArray(new Object[0]就是启动类
   load(context, sources.toArray(new Object[0]));
   
   //发布容器已加载事件
   listeners.contextLoaded(context);
}


public Set<Object> getAllSources() {
	Set<Object> allSources = new LinkedHashSet<>();
	if (!CollectionUtils.isEmpty(this.primarySources)) {
		allSources.addAll(this.primarySources);
	}
	if (!CollectionUtils.isEmpty(this.sources)) {
		allSources.addAll(this.sources);
	}
	return Collections.unmodifiableSet(allSources);
}

postProcessApplicationContext

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    //如果设置了是实例命名生成器,注册到Spring容器中
    if (this.beanNameGenerator != null) {
        context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
            this.beanNameGenerator);
    }
    // 如果设置了资源加载器,设置到Spring容器中
    if (this.resourceLoader != null) {
        if (context instanceof GenericApplicationContext) {
            ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
        }
        if (context instanceof DefaultResourceLoader) {
            ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
        }
    }
    if (this.addConversionService) {
        context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
    }
}

这里默认不执行任何逻辑,因为beanNameGeneratorresourceLoader默认为空。springBoot预留的扩展处理方式,配置上下文的 bean 生成器及资源加载器

load(context, sources.toArray(new Object[0]));

加载启动类

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    //创建 BeanDefinitionLoader    将上下文context强转为BeanDefinitionRegistry
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    loader.load();
}

//createBeanDefinitionLoader进入构造器
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
    Assert.notNull(registry, "Registry must not be null");
    Assert.notEmpty(sources, "Sources must not be empty");
    this.sources = sources;
    //注解形式的Bean定义读取器 比如:@Configuration @Bean @Component @Controller @Service等等
    this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
    
    //XML形式的Bean定义读取器
    this.xmlReader = new XmlBeanDefinitionReader(registry);
    if (isGroovyPresent()) {
        this.groovyReader = new GroovyBeanDefinitionReader(registry);
    }
    //类路径扫描器
    this.scanner = new ClassPathBeanDefinitionScanner(registry); 
    //扫描器添加排除过滤器
    this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}

private int load(Object source) {
    Assert.notNull(source, "Source must not be null");
    //如果是class类型,启用注解类型
    if (source instanceof Class<?>) {
        return load((Class<?>) source);
    }
    //如果是resource类型,启用xml解析
    if (source instanceof Resource) {
        return load((Resource) source);
    }
    //如果是package类型,启用扫描包,例如:@ComponentScan
    if (source instanceof Package) {
        return load((Package) source);
    }
    //如果是字符串类型,直接加载
    if (source instanceof CharSequence) {
        return load((CharSequence) source);
    }
    throw new IllegalArgumentException("Invalid source type " + source.getClass());
}

contextLoaded

发布容器已加载事件

public void contextLoaded(ConfigurableApplicationContext context) {
    for (ApplicationListener<?> listener : this.application.getListeners()) {
        if (listener instanceof ApplicationContextAware) {
            ((ApplicationContextAware) listener).setApplicationContext(context);
        }
        context.addApplicationListener(listener);
    }
    this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

上面会将spring.factories中的DelegatingApplicationListener放入容器上下文,从而该实例可以监听容器上下文发布的事件,也可以监听springboot中的事件(委派对象)

refreshContext

刷新容器,在这一步会根据条件创建web服务器

private void refreshContext(ConfigurableApplicationContext context) {
   //spring的核心方法
   refresh((ApplicationContext) context);
   if (this.registerShutdownHook) {
      try {
         context.registerShutdownHook();
      }
      catch (AccessControlException ex) {
         // Not allowed in some environments.
      }
   }
}

refresh()

synchronized (this.startupShutdownMonitor) {
    
    prepareRefresh();
   
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
   
    prepareBeanFactory(beanFactory);
    try {
        
        postProcessBeanFactory(beanFactory);
        
        invokeBeanFactoryPostProcessors(beanFactory);
        
        registerBeanPostProcessors(beanFactory);
        
        initMessageSource();
        
        initApplicationEventMulticaster();
  
       //关键代码,在这里选择并创建web服务器
        onRefresh();
        // Check for listener beans and register them.
        
        registerListeners();
       
        finishBeanFactoryInitialization(beanFactory);

        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 {

        resetCommonCaches();
    }
}
onRefresh()

我们看下我注释的关键代码onRefresh(),从上文可知,我们的servlet类型的spring容器是AnnotationConfigServletWebServerApplicationContext,看下这个类的继承关系

public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
      implements AnnotationConfigRegistry 
 }

AnnotationConfigServletWebServerApplicationContext本身没有实现onRefresh,这里由它的父类ServletWebServerApplicationContext实现

看下源码

@Override
protected void onRefresh() {
   super.onRefresh();
   try {
      createWebServer();
   }
   catch (Throwable ex) {
      throw new ApplicationContextException("Unable to start web server", ex);
   }
}
createWebServer()
private void createWebServer() {
   WebServer webServer = this.webServer;
   ServletContext servletContext = getServletContext();
   if (webServer == null && servletContext == null) {
   	  //这里会根据条件创建web服务器,详情可见springboot自动装配原理,一般情况下是TomcatServletWebServerFactory
      ServletWebServerFactory factory = getWebServerFactory();
      //这里就是具体子类的getWebServer,一般情况下是TomcatServletWebServerFactory.getWebServer
      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和DispatcherServlet,详见下发的spring自动装配Tomcat和DispatcherServlet

afterRefresh

刷新容器后的扩展接口,空方法

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。比如打印一些启动结束log,或者一些其它后置处理。

自定义starter

1、新建两个模块:

​ 命名规范,springboot自带的spring-boot-starter-xxx,自定义的xxx-spring-boot-starter

  • xxx-spring-boot-autoconfigure:自动配置核心代码
  • xxx-spring-boot-starter:管理依赖
    如果不需要将自动配置代码和依赖项管理分离开来,则可以将它们组合到一个模块中。

2、使用@ConfigurationProperties注入需要的配置

3、@Configuration + @Bean注册需要的bean,使用@EnableConfigurationProperties开启配置注入

4、利用META-INF/spring.factories导入@Configuration配置类(完全无侵入,但缺乏灵活性)

4.1、启动类使用@Import注解导入@Configuration配置类

4.1.1、EnableXXX 自定义注解使用@Import注解导入@Configuration配置类,启动类添加该注解

SpringBoot自动装配Tomcat和DispatcherServlet

一、简介

不知道大家第一次搭SpringBoot环境的时候,有没有觉得非常简单。无须各种的配置文件,无须各种繁杂的pom坐标,一个main方法,就能run起来了。与其他框架整合也贼方便,使用EnableXXXXX注解就可以搞起来了!

所以今天来讲讲SpringBoot是如何实现自动配置的~

二、原理

自动配置流程图

https://www.processon.com/view/link/5fc0abf67d9c082f447ce49b

image

源码的话就先从启动类开始入手:

@SpringBootApplication

@SpringBootApplication: Spring Boot应用标注在某个类上说明这个类是SpringBoot的主配置类,SpringBoot

需要运行这个类的main方法来启动SpringBoot应用;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

   
   @AliasFor(annotation = EnableAutoConfiguration.class)
   Class<?>[] exclude() default {};

   
   @AliasFor(annotation = EnableAutoConfiguration.class)
   String[] excludeName() default {};

   
   @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
   String[] scanBasePackages() default {};

   
   @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
   Class<?>[] scanBasePackageClasses() default {};


   @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
   Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;


   @AliasFor(annotation = Configuration.class)
   boolean proxyBeanMethods() default true;

}

@SpringBootConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;//默认使用CGLIB代理该类
}

@SpringBootConfiguration相当于Configuration,表明启动类也是一个配置类,可以配置@Bean

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

  
   Class<?>[] exclude() default {};

   
   String[] excludeName() default {};

}

@AutoConfigurationPackage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class) //手工注册bean
public @interface AutoConfigurationPackage {


   String[] basePackages() default {};


   Class<?>[] basePackageClasses() default {};

}

保存自动配置类以供之后的使用,比如给JPA entity扫描器用来扫描开发人员通过注解@Entity定义的entity类。

AutoConfigurationPackages.Registrar
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

   @Override
   public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
      register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
   }

   @Override
   public Set<Object> determineImports(AnnotationMetadata metadata) {
      return Collections.singleton(new PackageImports(metadata));
   }

}

@Import(AutoConfigurationImportSelector.class)

可以看到,在@EnableAutoConfiguration注解内使用到了@import注解来完成导入配置的功能,而AutoConfigurationImportSelector实现了DeferredImportSelectorSpring内部在解析@Import注解时会调用getAutoConfigurationEntry方法。

下面是2.3.2.RELEASE实现源码:

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
      ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {

   private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

   private static final String[] NO_IMPORTS = {};

   private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);

   private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

   private ConfigurableListableBeanFactory beanFactory;

   private Environment environment;

   private ClassLoader beanClassLoader;

   private ResourceLoader resourceLoader;

   private ConfigurationClassFilter configurationClassFilter;

   @Override
   public String[] selectImports(AnnotationMetadata annotationMetadata) {
      if (!isEnabled(annotationMetadata)) {
         return NO_IMPORTS;
      }
      //核心代码
      AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
      return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
   }
   
   protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
       if (!isEnabled(annotationMetadata)) {
          return EMPTY_ENTRY;
       }
       // 获取注解的属性值
       AnnotationAttributes attributes = getAttributes(annotationMetadata);
       // 从META-INF/spring.factories文件中获取EnableAutoConfiguration所对应的configurations
       List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
       // 去重
       configurations = removeDuplicates(configurations);
       // 从注解的exclude/excludeName属性中获取排除项
       Set<String> exclusions = getExclusions(annotationMetadata, attributes); 
       // 对于不属于AutoConfiguration的exclude报错
       checkExcludedClasses(configurations, exclusions);
       // 从configurations去除exclusions
       configurations.removeAll(exclusions);
       // 通过读取spring.factories 中的OnBeanCondition\OnClassCondition\OnWebApplicationCondition进行过滤
       // 由所有AutoConfigurationImportFilter类的实例再进行一次筛选
       configurations = getConfigurationClassFilter().filter(configurations);
       // 这个方法是调用实现了AutoConfigurationImportListener  的bean..  分别把候选的配置名单,和排除的配置名单传进去做扩展
       fireAutoConfigurationImportEvents(configurations, exclusions);
       // 返回(configurations, exclusions)组
       return new AutoConfigurationEntry(configurations, exclusions);
    }
  
}

getAutoConfigurationEntry方法进行扫描具有META-INF/spring.factories文件的jar包。

image

任何一个springboot应用,都会引入spring-boot-autoconfigure,而spring.factories文件就在该包下面。spring.factories文件是Key=Value形式,多个Value时使用,隔开,该文件中定义了关于初始化,监听器等信息,而真正使自动配置生效的key是org.springframework.boot.autoconfigure.EnableAutoConfiguration,如下所示:

等同于 @Import

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,\
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\
# 这里就是自动装配DispatcherServlet
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
# 这里就是自动装配Web服务器,默认是tomcat
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration

# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.data.redis.RedisUrlSyntaxFailureAnalyzer,\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\
org.springframework.boot.autoconfigure.r2dbc.ConnectionFactoryBeanCreationFailureAnalyzer,\
org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer

# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.servlet.JspTemplateAvailabilityProvider

ServletWebServerFactoryAutoConfiguration

这里会根据条件创建web服务器,详情可见springboot自动装配原理,简单介绍一下,这里会自动装配ServletWebServerFactoryAutoConfiguration类,@Import了tomcat等3种容器

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
//这里导入了一个BeanPostProcessorsRegistrar和ServletWebServerFactoryConfiguration下面三个不同的服务器
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

   @Bean
   public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
      return new ServletWebServerFactoryCustomizer(serverProperties);
   }

   @Bean
   @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
   public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
         ServerProperties serverProperties) {
      return new TomcatServletWebServerFactoryCustomizer(serverProperties);
   }

   @Bean
   @ConditionalOnMissingFilterBean(ForwardedHeaderFilter.class)
   @ConditionalOnProperty(value = "server.forward-headers-strategy", havingValue = "framework")
   public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
      ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
      FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
      registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
      registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
      return registration;
   }

   /**注册一个WebServerFactoryCustomizerBeanPostProcessor
    * Registers a {@link WebServerFactoryCustomizerBeanPostProcessor}. Registered via
    * {@link ImportBeanDefinitionRegistrar} for early registration.
    */
   public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

      private ConfigurableListableBeanFactory beanFactory;

      @Override
      public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
         if (beanFactory instanceof ConfigurableListableBeanFactory) {
            this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
         }
      }

      @Override
      public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
            BeanDefinitionRegistry registry) {
         if (this.beanFactory == null) {
            return;
         }
         registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
               WebServerFactoryCustomizerBeanPostProcessor.class);
         registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
               ErrorPageRegistrarBeanPostProcessor.class);
      }

      private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
         if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
            beanDefinition.setSynthetic(true);
            registry.registerBeanDefinition(name, beanDefinition);
         }
      }

   }

}

ServletWebServerFactoryConfiguration

根据条件判断引入哪个服务器

@Configuration(proxyBeanMethods = false)
class ServletWebServerFactoryConfiguration {

   @Configuration(proxyBeanMethods = false)
   @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;
      }

   }

   /**
    * Nested configuration if Jetty is being used.
    */
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
   @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
   static class EmbeddedJetty {

      @Bean
      JettyServletWebServerFactory JettyServletWebServerFactory(
            ObjectProvider<JettyServerCustomizer> serverCustomizers) {
         JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
         factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().collect(Collectors.toList()));
         return factory;
      }

   }

   /**
    * Nested configuration if Undertow is being used.
    */
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
   @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
   static class EmbeddedUndertow {

      @Bean
      UndertowServletWebServerFactory undertowServletWebServerFactory(
            ObjectProvider<UndertowDeploymentInfoCustomizer> deploymentInfoCustomizers,
            ObjectProvider<UndertowBuilderCustomizer> builderCustomizers) {
         UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
         factory.getDeploymentInfoCustomizers()
               .addAll(deploymentInfoCustomizers.orderedStream().collect(Collectors.toList()));
         factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().collect(Collectors.toList()));
         return factory;
      }

   }

}
TomcatServletWebServerFactory

通过getWebServer新建一个tomcat,并返回

public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory
      implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
      
      
    //TomcatServletWebServerFactory.getWebServer
	@Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		if (this.disableMBeanRegistry) {
			Registry.disableRegistry();
		}
		// new 一个tomcat实例
		Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		// tomcat中的Connector组件
		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);
		}
		//DispatcherServlet就是在这里初始化的
		prepareContext(tomcat.getHost(), initializers);
		// tomcat的start,和socket启动阻塞都在这个方法里
		return getTomcatWebServer(tomcat);
	}
      
      
      protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
        return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
    }
    
    public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
        this.monitor = new Object();
        this.serviceConnectors = new HashMap();
        Assert.notNull(tomcat, "Tomcat Server must not be null");
        this.tomcat = tomcat;
        this.autoStart = autoStart;
        this.gracefulShutdown = shutdown == Shutdown.GRACEFUL ? new GracefulShutdown(tomcat) : null;
        this.initialize();
    }
    
    
    
    private void initialize() throws WebServerException {
        logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
        synchronized(this.monitor) {
            try {
                this.addInstanceIdToEngineName();
                Context context = this.findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource()) && "start".equals(event.getType())) {
                        this.removeServiceConnectors();
                    }

                });                 
                // tomcat就是在这里启动的
                this.tomcat.start();
                this.rethrowDeferredStartupExceptions();

                try {
                    ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
                } catch (NamingException var5) {
                }
                // 这里就是设置socket监听
                this.startDaemonAwaitThread();
            } catch (Exception var6) {
                this.stopSilently();
                this.destroySilently();
                throw new WebServerException("Unable to start embedded Tomcat", var6);
            }

        }
    }
    
    
    
    private void startDaemonAwaitThread() {
        Thread awaitThread = new Thread("container-" + containerCounter.get()) {
            public void run() {
                TomcatWebServer.this.tomcat.getServer().await();
            }
        };
        awaitThread.setContextClassLoader(this.getClass().getClassLoader());
        awaitThread.setDaemon(false);
        awaitThread.start();
    }

 }
      

上面就是内嵌tomcat的启动过程,下面分析下DispatcherServlet加载的源码分析。

DispatcherServletAutoConfiguration

springboot自动装配了DispatcherServletAutoConfiguration,源码如下

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

   /*
    * The bean name for a DispatcherServlet that will be mapped to the root URL "/"
    */
   public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

   /*
    * The bean name for a ServletRegistrationBean for the DispatcherServlet "/"
    */
   public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

   @Configuration(proxyBeanMethods = false)
   @Conditional(DefaultDispatcherServletCondition.class)
   @ConditionalOnClass(ServletRegistration.class)
   @EnableConfigurationProperties(WebMvcProperties.class)
   protected static class DispatcherServletConfiguration {

	  //这里就是将DispatcherServlet注入spring容器
      @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
      public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
         DispatcherServlet dispatcherServlet = new DispatcherServlet();
         dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
         dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
         dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
         dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
         dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
         return dispatcherServlet;
      }

      @Bean
      @ConditionalOnBean(MultipartResolver.class)
      @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
      public MultipartResolver multipartResolver(MultipartResolver resolver) {
         // Detect if the user has created a MultipartResolver but named it incorrectly
         return resolver;
      }

   }

   @Configuration(proxyBeanMethods = false)
   @Conditional(DispatcherServletRegistrationCondition.class)
   @ConditionalOnClass(ServletRegistration.class)
   @EnableConfigurationProperties(WebMvcProperties.class)
   @Import(DispatcherServletConfiguration.class)
   protected static class DispatcherServletRegistrationConfiguration {

		//DispatcherServletRegistrationBean就是将DispatcherServlet配置到ServletContext中去
      @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
      @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
      public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
            WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
         DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
               webMvcProperties.getServlet().getPath());
         registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
         registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
         multipartConfig.ifAvailable(registration::setMultipartConfig);
         return registration;
      }

   }

   @Order(Ordered.LOWEST_PRECEDENCE - 10)
   private static class DefaultDispatcherServletCondition extends SpringBootCondition {

      @Override
      public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
         ConditionMessage.Builder message = ConditionMessage.forCondition("Default DispatcherServlet");
         ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
         List<String> dispatchServletBeans = Arrays
               .asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
         if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
            return ConditionOutcome
                  .noMatch(message.found("dispatcher servlet bean").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
         }
         if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
            return ConditionOutcome.noMatch(
                  message.found("non dispatcher servlet bean").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
         }
         if (dispatchServletBeans.isEmpty()) {
            return ConditionOutcome.match(message.didNotFind("dispatcher servlet beans").atAll());
         }
         return ConditionOutcome.match(message.found("dispatcher servlet bean", "dispatcher servlet beans")
               .items(Style.QUOTE, dispatchServletBeans)
               .append("and none is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
      }

   }

   @Order(Ordered.LOWEST_PRECEDENCE - 10)
   private static class DispatcherServletRegistrationCondition extends SpringBootCondition {

      @Override
      public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
         ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
         ConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);
         if (!outcome.isMatch()) {
            return outcome;
         }
         return checkServletRegistration(beanFactory);
      }

      private ConditionOutcome checkDefaultDispatcherName(ConfigurableListableBeanFactory beanFactory) {
         List<String> servlets = Arrays
               .asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
         boolean containsDispatcherBean = beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
         if (containsDispatcherBean && !servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
            return ConditionOutcome.noMatch(
                  startMessage().found("non dispatcher servlet").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
         }
         return ConditionOutcome.match();
      }

      private ConditionOutcome checkServletRegistration(ConfigurableListableBeanFactory beanFactory) {
         ConditionMessage.Builder message = startMessage();
         List<String> registrations = Arrays
               .asList(beanFactory.getBeanNamesForType(ServletRegistrationBean.class, false, false));
         boolean containsDispatcherRegistrationBean = beanFactory
               .containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
         if (registrations.isEmpty()) {
            if (containsDispatcherRegistrationBean) {
               return ConditionOutcome.noMatch(message.found("non servlet registration bean")
                     .items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
            }
            return ConditionOutcome.match(message.didNotFind("servlet registration bean").atAll());
         }
         if (registrations.contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {
            return ConditionOutcome.noMatch(message.found("servlet registration bean")
                  .items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
         }
         if (containsDispatcherRegistrationBean) {
            return ConditionOutcome.noMatch(message.found("non servlet registration bean")
                  .items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
         }
         return ConditionOutcome.match(message.found("servlet registration beans").items(Style.QUOTE, registrations)
               .append("and none is named " + DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
      }

      private ConditionMessage.Builder startMessage() {
         return ConditionMessage.forCondition("DispatcherServlet Registration");
      }

   }

}

DispatcherServletRegistrationBean

DispatcherServletRegistrationBean非常重要,我们看下他的类结构

image

可以看出它实现了ServletContextInitializer接口,因此在web容器启动时,就会调用它的onStartup()方法

具体实现内容由父类RegistrationBean处理

onStartup
@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);
}

它里面有一个注册方法this.register(description, servletContext); ,这个方法实在实现子类DynamicRegistrationBean中的代码如下

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

这个register方法中又有一个this.addRegistration(description, servletContext); 方法的调用,这个方法还是子类中调用的。子类是ServletRegistrationBean

到这里才真正看到Servlet的影子。

protected Dynamic addRegistration(String description, ServletContext servletContext) {
        String name = this.getServletName();
        return servletContext.addServlet(name, this.servlet);
    }

这样我们可以看到将description设置到了ServletContext去,这个description一定就是DispatcherServlet,我们继续看下去

configure

@Override
protected void configure(ServletRegistration.Dynamic registration) {
   super.configure(registration);
   String[] urlMapping = StringUtils.toStringArray(this.urlMappings);
   if (urlMapping.length == 0 && this.alwaysMapUrl) {
      urlMapping = DEFAULT_MAPPINGS;
   }
   //urlMapping="/"
   if (!ObjectUtils.isEmpty(urlMapping)) {
      registration.addMapping(urlMapping);
   }
   registration.setLoadOnStartup(this.loadOnStartup);
   if (this.multipartConfig != null) {
      registration.setMultipartConfig(this.multipartConfig);
   }
}

在registration.addMapping(urlMapping);会注册DispatcherServlet,而DispatcherServlet就是自动装配的时候注入到spring容器中去的

细节如下:

在上面启动流程的createServer()方法中有一行调用: this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});

参数是一个ServletContextInitializer 的数组,是从getSelfInitializer() 方法中得到,DispatcherServlet就是这里加载的。

// 这里返回lambda 表达式,ServletContextInitializer是个一个函数式接口,里面只有一个onStartup方法,这里相当于返回了一个接口的实例
// 这个实例的onStartup的逻辑就是下面的selfInitialize方法, 调用getSerlfInitializer方法的时候,下面那个方法不会马上执行。
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
   return this::selfInitialize;
}

private void selfInitialize(ServletContext servletContext) throws ServletException {
   prepareWebApplicationContext(servletContext);
   registerApplicationScope(servletContext);
   WebApplicationContextUtils.registerEnvironmentBeans(getBeanFactory(), servletContext);
   // 这里就是找ServletContextInitializer的实现类
   for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
   	// 这里遍历调用onStarup方法
      beans.onStartup(servletContext);
   }
}

// 这里就是找ServletContextInitializer的实现类
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
	return new ServletContextInitializerBeans(getBeanFactory());
}

回到上面的getWebServer方法,它的参数就是getSelfInitializer()得到的lamda表达式。在调用 this.prepareContext(tomcat.getHost(), initializers);

时初始化DispatcherServlet。这是在TomcatServletWebServerFactory 中的。

protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
   File documentRoot = getValidDocumentRoot();
    // 这个new出来的类,继承自tomcat中的StandardContext
    // tomcat在初始化过程中会触发StandardContext中的一个全局变量 Map<ServletContainerInitializer,Set<Class<?>>> initializers 
   // 遍历它并执行ServletContainerInitializer.onStartup方法  这个过程在springmvc初始化servlet中有提到过
   TomcatEmbeddedContext context = new TomcatEmbeddedContext();
   if (documentRoot != null) {
      context.setResources(new LoaderHidingResourceRoot(context));
   }
   context.setName(getContextPath());
   context.setDisplayName(getDisplayName());
   context.setPath(getContextPath());
   File docBase = (documentRoot != null) ? documentRoot : createTempDir("tomcat-docbase");
   context.setDocBase(docBase.getAbsolutePath());
   context.addLifecycleListener(new FixContextListener());
   context.setParentClassLoader((this.resourceLoader != null) ? this.resourceLoader.getClassLoader()
         : ClassUtils.getDefaultClassLoader());
   resetDefaultLocaleMapping(context);
   addLocaleMappings(context);
   try {
      context.setCreateUploadTargets(true);
   }
   catch (NoSuchMethodError ex) {
      // Tomcat is < 8.5.39. Continue.
   }
   configureTldSkipPatterns(context);
   WebappLoader loader = new WebappLoader();
   loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName());
   loader.setDelegate(true);
   context.setLoader(loader);
   if (isRegisterDefaultServlet()) {
      addDefaultServlet(context);
   }
   if (shouldRegisterJspServlet()) {
      addJspServlet(context);
      addJasperInitializer(context);
   }
   context.addLifecycleListener(new StaticResourceConfigurer(context));
   ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);
   host.addChild(context);
   // 到这里 initializersToUse还是上面的lambda表达式,只是做了一些合并操作 ,执行也是在这里面的
   configureContext(context, initializersToUse);
   postProcessContext(context);
}

configureContext

protected void configureContext(Context context, ServletContextInitializer[] initializers) {          
// 它就实现了ServletContainerInitializer的接口  并通过构造函数把上面的那个lambda表达式传递进去        
//  它里面的onStartup方法,就会在执行的时候遍历这个数组中的实例执行其onStartup方法,也就时执行了上面的lambda表达式
        TomcatStarter starter = new TomcatStarter(initializers);
        if (context instanceof TomcatEmbeddedContext) {
            TomcatEmbeddedContext embeddedContext = (TomcatEmbeddedContext)context;
            embeddedContext.setStarter(starter);
            embeddedContext.setFailCtxIfServletStartFails(true);
        }
        // 这个context就是ServletContext的子类,把starter加进去
        context.addServletContainerInitializer(starter, NO_CLASSES);
        Iterator var7 = this.contextLifecycleListeners.iterator();

        while(var7.hasNext()) {
            LifecycleListener lifecycleListener = (LifecycleListener)var7.next();
            context.addLifecycleListener(lifecycleListener);
        }

        var7 = this.contextValves.iterator();

        while(var7.hasNext()) {
            Valve valve = (Valve)var7.next();
            context.getPipeline().addValve(valve);
        }

        var7 = this.getErrorPages().iterator();

        while(var7.hasNext()) {
            ErrorPage errorPage = (ErrorPage)var7.next();
            org.apache.tomcat.util.descriptor.web.ErrorPage tomcatErrorPage = new org.apache.tomcat.util.descriptor.web.ErrorPage();
            tomcatErrorPage.setLocation(errorPage.getPath());
            tomcatErrorPage.setErrorCode(errorPage.getStatusCode());
            tomcatErrorPage.setExceptionType(errorPage.getExceptionName());
            context.addErrorPage(tomcatErrorPage);
        }

        var7 = this.getMimeMappings().iterator();

        while(var7.hasNext()) {
            Mapping mapping = (Mapping)var7.next();
            context.addMimeMapping(mapping.getExtension(), mapping.getMimeType());
        }

        this.configureSession(context);
        (new DisableReferenceClearingContextCustomizer()).customize(context);
        var7 = this.getWebListenerClassNames().iterator();

        while(var7.hasNext()) {
            String webListenerClassName = (String)var7.next();
            context.addApplicationListener(webListenerClassName);
        }

        var7 = this.tomcatContextCustomizers.iterator();

        while(var7.hasNext()) {
            TomcatContextCustomizer customizer = (TomcatContextCustomizer)var7.next();
            customizer.customize(context);
        }

    }

把它和上面的ServletRegistrationBean 关联起来的是下面的一个Bean

这个dispatcherServletRegistration 的bean中会自动注入上面创建的*DispatcherServlet,然后把它传递给了*DispatcherServletRegistrationBean构造函数。

总结一下:

初始化SpringApplication

  • 从spring.factories 读取自动配置 listener ApplicationContextInitializer
  • 利用反射将启动类实例化并包装成SpringApplication 对象

运行run方法

  • 读取 环境变量 配置信息.....
  • 创建springApplication上下文:ServletWebServerApplicationContext
  • 预初始化上下文 : 读取启动类
  • 调用refresh 刷新容器
  • 加载所有的自动配置类,在refresh的onRefresh()中会根据条件自动装配web容器和Dispatcher,并在Tomcat启动时将Dispatcher设置到ServletContext中去

ps.在这个过程中springboot会调用很多监听器对外进行扩展,有机会再研究吧

posted on 2022-03-08 23:40  路仁甲  阅读(80)  评论(0编辑  收藏  举报