SpringBoot 启动方法

入口

  • 通常一个简单的 SpringBoot 基础项目我们会有如下代码
  1. @SpringBootApplication
  2. @RestController
  3. @RequestMapping("/")
  4. public class Application {
  5. public static void main(String[] args) {
  6. SpringApplication.run(Application.class, args);
  7. }
  8. }
  • 值得关注的有SpringApplication.run以及注解@SpringBootApplication

run 方法

  1. public ConfigurableApplicationContext run(String... args) {
  2. // 秒表
  3. StopWatch stopWatch = new StopWatch();
  4. stopWatch.start();
  5. ConfigurableApplicationContext context = null;
  6. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  7. configureHeadlessProperty();
  8. // 获取监听器
  9. SpringApplicationRunListeners listeners = getRunListeners(args);
  10. // 监听器启动
  11. listeners.starting();
  12. try {
  13. // application 启动参数列表
  14. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  15. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  16. // 配置忽略的bean信息
  17. configureIgnoreBeanInfo(environment);
  18. Banner printedBanner = printBanner(environment);
  19. // 创建应用上下文
  20. context = createApplicationContext();
  21. exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
  22. new Class[] { ConfigurableApplicationContext.class }, context);
  23. // 准备上下文,装配bean
  24. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  25. // 上下文刷新
  26. refreshContext(context);
  27. // 刷新后做什么
  28. afterRefresh(context, applicationArguments);
  29. stopWatch.stop();
  30. if (this.logStartupInfo) {
  31. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  32. }
  33. // 监听器开始了
  34. listeners.started(context);
  35. // 唤醒
  36. callRunners(context, applicationArguments);
  37. }
  38. catch (Throwable ex) {
  39. handleRunFailure(context, ex, exceptionReporters, listeners);
  40. throw new IllegalStateException(ex);
  41. }
  42. try {
  43. // 监听器正式运行
  44. listeners.running(context);
  45. }
  46. catch (Throwable ex) {
  47. handleRunFailure(context, ex, exceptionReporters, null);
  48. throw new IllegalStateException(ex);
  49. }
  50. return context;
  51. }

getRunListeners

  • 获取监听器
  1. private SpringApplicationRunListeners getRunListeners(String[] args) {
  2. Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
  3. // 获取 Spring Factory 实例对象
  4. return new SpringApplicationRunListeners(logger,
  5. getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
  6. }
  7. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  8. ClassLoader classLoader = getClassLoader();
  9. // Use names and ensure unique to protect against duplicates
  10. // 读取 spring.factories
  11. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  12. // 创建SpringFactory实例
  13. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  14. /**
  15. * 排序 {@link Ordered}
  16. */
  17. AnnotationAwareOrderComparator.sort(instances);
  18. return instances;
  19. }

createSpringFactoriesInstances

  1. @SuppressWarnings("unchecked")
  2. private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
  3. ClassLoader classLoader, Object[] args, Set<String> names) {
  4. // 初始化
  5. List<T> instances = new ArrayList<>(names.size());
  6. for (String name : names) {
  7. try {
  8. // 通过名字创建类的class对象
  9. Class<?> instanceClass = ClassUtils.forName(name, classLoader);
  10. Assert.isAssignable(type, instanceClass);
  11. // 构造器获取
  12. Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
  13. // 创建具体实例
  14. T instance = (T) BeanUtils.instantiateClass(constructor, args);
  15. // 加入实例表中
  16. instances.add(instance);
  17. }
  18. catch (Throwable ex) {
  19. throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
  20. }
  21. }
  22. return instances;
  23. }
  • SpringFactoriesLoader.loadFactoryNames(type, classLoader) 是 spring 提供的方法,主要目的是读取spring.factories文件
    • 读取需要创建的内容

image-20200318080601725

  • 创建完成

    image-20200318080901881

  • AnnotationAwareOrderComparator.sort(instances)排序

    • 通过 spring 的源码我们知道这个方法是根据order的数字大小进行排序,观察

      SharedMetadataReaderFactoryContextInitializer

      image-20200318081112670

    • 同样的再找一个DelegatingApplicationContextInitializer

      image-20200318081322781

  • 下图中的所有类都有 Order 数值返回

    排序前:

image-20200318081352639

排序后:

image-20200318081458019

listeners.starting()

  • SpringApplicationRunListeners : org.springframework.boot.SpringApplicationRunListeners 这个类是org.springframework.boot.SpringApplicationRunListener的集合表现形式

    1. class SpringApplicationRunListeners {
    2. private final List<SpringApplicationRunListener> listeners;
    3. SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
    4. this.log = log;
    5. this.listeners = new ArrayList<>(listeners);
    6. }
    7. void starting() {
    8. for (SpringApplicationRunListener listener : this.listeners) {
    9. listener.starting();
    10. }
    11. }
    12. }
    • 这里主要是启动org.springframework.boot.SpringApplicationRunListener#starting方法,只有一个实现org.springframework.boot.context.event.EventPublishingRunListener#starting

prepareEnvironment

  1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
  2. ApplicationArguments applicationArguments) {
  3. // Create and configure the environment
  4. // 得到一个环境
  5. ConfigurableEnvironment environment = getOrCreateEnvironment();
  6. // 配置环境
  7. configureEnvironment(environment, applicationArguments.getSourceArgs());
  8. ConfigurationPropertySources.attach(environment);
  9. listeners.environmentPrepared(environment);
  10. // 绑定springBoot应用
  11. bindToSpringApplication(environment);
  12. // 是否创建自定义环境
  13. if (!this.isCustomEnvironment) {
  14. environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
  15. deduceEnvironmentClass());
  16. }
  17. ConfigurationPropertySources.attach(environment);
  18. return environment;
  19. }

configureIgnoreBeanInfo

  • 获取spring.beaninfo.ignore并且设置到环境信息中
  1. private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {
  2. if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {
  3. Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE);
  4. System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString());
  5. }
  6. }

printBanner

  1. private Banner printBanner(ConfigurableEnvironment environment) {
  2. if (this.bannerMode == Banner.Mode.OFF) {
  3. return null;
  4. }
  5. ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
  6. : new DefaultResourceLoader(getClassLoader());
  7. // 创建打印器
  8. SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
  9. if (this.bannerMode == Mode.LOG) {
  10. // 输出
  11. return bannerPrinter.print(environment, this.mainApplicationClass, logger);
  12. }
  13. // 输出
  14. return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
  15. }
  1. Banner print(Environment environment, Class<?> sourceClass, PrintStream out) {
  2. Banner banner = getBanner(environment);
  3. banner.printBanner(environment, sourceClass, out);
  4. return new PrintedBanner(banner, sourceClass);
  5. }
  • 最终输出内容类:org.springframework.boot.SpringBootBanner

    1. class SpringBootBanner implements Banner {
    2. private static final String[] BANNER = { "", " . ____ _ __ _ _",
    3. " /\\\\ / ___'_ __ _ _(_)_ __ __ _ \\ \\ \\ \\", "( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\",
    4. " \\\\/ ___)| |_)| | | | | || (_| | ) ) ) )", " ' |____| .__|_| |_|_| |_\\__, | / / / /",
    5. " =========|_|==============|___/=/_/_/_/" };
    6. private static final String SPRING_BOOT = " :: Spring Boot :: ";
    7. private static final int STRAP_LINE_SIZE = 42;
    8. @Override
    9. public void printBanner(Environment environment, Class<?> sourceClass, PrintStream printStream) {
    10. for (String line : BANNER) {
    11. printStream.println(line);
    12. }
    13. String version = SpringBootVersion.getVersion();
    14. version = (version != null) ? " (v" + version + ")" : "";
    15. StringBuilder padding = new StringBuilder();
    16. while (padding.length() < STRAP_LINE_SIZE - (version.length() + SPRING_BOOT.length())) {
    17. padding.append(" ");
    18. }
    19. printStream.println(AnsiOutput.toString(AnsiColor.GREEN, SPRING_BOOT, AnsiColor.DEFAULT, padding.toString(),
    20. AnsiStyle.FAINT, version));
    21. printStream.println();
    22. }
    23. }

createApplicationContext

  1. protected ConfigurableApplicationContext createApplicationContext() {
  2. // 获取上下文类
  3. Class<?> contextClass = this.applicationContextClass;
  4. if (contextClass == null) {
  5. try {
  6. // 根据不同类型选择创建的实例
  7. switch (this.webApplicationType) {
  8. case SERVLET:
  9. contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
  10. break;
  11. case REACTIVE:
  12. contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
  13. break;
  14. default:
  15. contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
  16. }
  17. }
  18. catch (ClassNotFoundException ex) {
  19. throw new IllegalStateException(
  20. "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
  21. }
  22. }
  23. return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
  24. }
  • this.applicationContextClass 初始化方法
  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  5. // 设置 web应用类型
  6. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  7. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  8. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  9. this.mainApplicationClass = deduceMainApplicationClass();
  10. }
  • org.springframework.boot.WebApplicationType#deduceFromClasspath
  1. static WebApplicationType deduceFromClasspath() {
  2. if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
  3. && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
  4. return WebApplicationType.REACTIVE;
  5. }
  6. for (String className : SERVLET_INDICATOR_CLASSES) {
  7. if (!ClassUtils.isPresent(className, null)) {
  8. return WebApplicationType.NONE;
  9. }
  10. }
  11. return WebApplicationType.SERVLET;
  12. }

exceptionReporters

image-20200318085243888

prepareContext

  1. private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
  2. SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  3. // 上下文中设置环境
  4. context.setEnvironment(environment);
  5. // 上下文处理
  6. postProcessApplicationContext(context);
  7. // 初始化
  8. applyInitializers(context);
  9. // 监听器中放入上下文
  10. listeners.contextPrepared(context);
  11. if (this.logStartupInfo) {
  12. logStartupInfo(context.getParent() == null);
  13. logStartupProfileInfo(context);
  14. }
  15. // Add boot specific singleton beans
  16. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  17. // 单例对象注册
  18. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  19. if (printedBanner != null) {
  20. beanFactory.registerSingleton("springBootBanner", printedBanner);
  21. }
  22. if (beanFactory instanceof DefaultListableBeanFactory) {
  23. ((DefaultListableBeanFactory) beanFactory)
  24. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  25. }
  26. if (this.lazyInitialization) {
  27. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  28. }
  29. // Load the sources
  30. Set<Object> sources = getAllSources();
  31. Assert.notEmpty(sources, "Sources must not be empty");
  32. // 加载上下文
  33. load(context, sources.toArray(new Object[0]));
  34. // 监听器做加载上下文操作
  35. listeners.contextLoaded(context);
  36. }
  • set方法就不说了

postProcessApplicationContext

  1. protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
  2. if (this.beanNameGenerator != null) {
  3. // 注册 beanName 的生成器
  4. context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
  5. this.beanNameGenerator);
  6. }
  7. if (this.resourceLoader != null) {
  8. if (context instanceof GenericApplicationContext) {
  9. // 设置资源加载器
  10. ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
  11. }
  12. if (context instanceof DefaultResourceLoader) {
  13. // 设置类加载器
  14. ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
  15. }
  16. }
  17. if (this.addConversionService) {
  18. // 转换服务
  19. context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
  20. }
  21. }
  • 看一下最终设置完成后的 context

    1. context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());

image-20200318090128983

image-20200318090312626

applyInitializers

  • 初始化应用上下文
  1. @SuppressWarnings({ "rawtypes", "unchecked" })
  2. protected void applyInitializers(ConfigurableApplicationContext context) {
  3. for (ApplicationContextInitializer initializer : getInitializers()) {
  4. Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
  5. ApplicationContextInitializer.class);
  6. Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
  7. initializer.initialize(context);
  8. }
  9. }
  • 初始化 List<ApplicationListener<?>> listeners: setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

  • 获取 List<ApplicationListener<?>> listeners: public Set<ApplicationListener<?>> getListeners() { return asUnmodifiableOrderedSet(this.listeners);}

  • 数据结果

image-20200318090935285

  • 子类的具体实现不展开了

getAllSources

  1. public Set<Object> getAllSources() {
  2. Set<Object> allSources = new LinkedHashSet<>();
  3. if (!CollectionUtils.isEmpty(this.primarySources)) {
  4. allSources.addAll(this.primarySources);
  5. }
  6. if (!CollectionUtils.isEmpty(this.sources)) {
  7. allSources.addAll(this.sources);
  8. }
  9. return Collections.unmodifiableSet(allSources);
  10. }
  • primarySources 就是我们的项目启动类,在SpringApplication的构造器中有this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources))

image-20200318091558233

load

  • 加载 bean 到应用上下文
  1. protected void load(ApplicationContext context, Object[] sources) {
  2. if (logger.isDebugEnabled()) {
  3. logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
  4. }
  5. // bean定义加载器
  6. BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
  7. if (this.beanNameGenerator != null) {
  8. // 设置 beanName生成器
  9. loader.setBeanNameGenerator(this.beanNameGenerator);
  10. }
  11. if (this.resourceLoader != null) {
  12. // 设置 资源加载器
  13. loader.setResourceLoader(this.resourceLoader);
  14. }
  15. if (this.environment != null) {
  16. // 设置环境
  17. loader.setEnvironment(this.environment);
  18. }
  19. // 加载
  20. loader.load();
  21. }
  1. int load() {
  2. int count = 0;
  3. for (Object source : this.sources) {
  4. count += load(source);
  5. }
  6. return count;
  7. }
  1. private int load(Object source) {
  2. Assert.notNull(source, "Source must not be null");
  3. if (source instanceof Class<?>) {
  4. return load((Class<?>) source);
  5. }
  6. if (source instanceof Resource) {
  7. return load((Resource) source);
  8. }
  9. if (source instanceof Package) {
  10. return load((Package) source);
  11. }
  12. if (source instanceof CharSequence) {
  13. return load((CharSequence) source);
  14. }
  15. throw new IllegalArgumentException("Invalid source type " + source.getClass());
  16. }
  • 通过前文我们已经知道 source就是一个 class

    image-20200318092027020

  1. private int load(Class<?> source) {
  2. if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
  3. // Any GroovyLoaders added in beans{} DSL can contribute beans here
  4. GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
  5. load(loader);
  6. }
  7. // 是否为组件
  8. if (isComponent(source)) {
  9. this.annotatedReader.register(source);
  10. return 1;
  11. }
  12. return 0;
  13. }
  • 我们的启动类是一个组件,直接注册完成返回 1

listeners.contextLoaded(context)

  • 监听器行为: 在上下文资源加载后做一些事情

refreshContext

  • 上下文刷新
  1. private void refreshContext(ConfigurableApplicationContext context) {
  2. refresh(context);
  3. if (this.registerShutdownHook) {
  4. try {
  5. context.registerShutdownHook();
  6. }
  7. catch (AccessControlException ex) {
  8. // Not allowed in some environments.
  9. }
  10. }
  11. }
  1. /**
  2. * Refresh the underlying {@link ApplicationContext}.
  3. * @param applicationContext the application context to refresh
  4. */
  5. protected void refresh(ApplicationContext applicationContext) {
  6. Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
  7. ((AbstractApplicationContext) applicationContext).refresh();
  8. }
  • 最终来到了org.springframework.context.support.AbstractApplicationContext#refresh方法,此方法是 spring 的一个方法,此处不在阐述

afterRefresh

  • 刷新上下文之后做的事情,空的没有实现

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

stopWatch.stop()

  • 秒表结束

listeners.started(context)

  • 各类监听器启动

callRunners

  • 两种 runner 启动ApplicationRunnerCommandLineRunner
  1. private void callRunners(ApplicationContext context, ApplicationArguments args) {
  2. List<Object> runners = new ArrayList<>();
  3. runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  4. runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  5. AnnotationAwareOrderComparator.sort(runners);
  6. for (Object runner : new LinkedHashSet<>(runners)) {
  7. if (runner instanceof ApplicationRunner) {
  8. callRunner((ApplicationRunner) runner, args);
  9. }
  10. if (runner instanceof CommandLineRunner) {
  11. callRunner((CommandLineRunner) runner, args);
  12. }
  13. }
  14. }
  1. private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
  2. try {
  3. (runner).run(args);
  4. }
  5. catch (Exception ex) {
  6. throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
  7. }
  8. }

listeners.running(context)

  • 监听器正式开始工作