整个启动流程包含,推断 WEB 应用类型,设置初始化器,设置 ApplicationListener 监听器,获取并启动 SpringApplicationRunListener 类,准备 Spring 环境,创建并执行 banner 打印类,创建应用上下文,准备应用上下文,刷新应用上下文,刷新应用上下文之后的调用,执行所有的 Runner 运行器。

  1. @SpringBootApplication
  2. public class MainApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(MainApplication.class, args);
  5. }
  6. }
  • 初始化主要加载资源类到集合中
  • 推断当前 WEB 应用类型(NONE、SERVLET、REACTIVE)
  • 设置应用上下文初始化器
  • 设置 ApplicationListener 监听器
  • 推断主入口应用类
  1. // 创建一个新的实例,这个应用上下文将从指定的来源加载 Bean
  2. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  3. // 初始化资源加载器,默认 null
  4. this.resourceLoader = resourceLoader;
  5. // 断言主资源不能为空
  6. Assert.notNull(primarySources, "PrimarySources must not be null");
  7. // 初始化主要加载资源类集合并去重
  8. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  9. // 推断当前 WEB 应用类型,NONE、SERVLET、REACTIVE
  10. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  11. // 加载引导程序(2.4.0增加的功能)
  12. this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
  13. // 设置初始化器
  14. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  15. // 设置监听器
  16. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  17. // 推断主入口应用类
  18. this.mainApplicationClass = deduceMainApplicationClass();
  19. }
  • 创建引导上下文
  • 获取并启动所有 SpringApplicationRunListener 对象
  • 创建默认的应用参数类
  • 准备 Spring 应用环境
  • 创建并执行 banner 打印类
  • 创建应用上下文
  • 准备应用上下文
  • 刷新应用上下文
  1. public ConfigurableApplicationContext run(String... args) {
  2. // 创建并启动计时监控类
  3. StopWatch stopWatch = new StopWatch();
  4. stopWatch.start();
  5. // 创建引导上下文
  6. DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  7. ConfigurableApplicationContext context = null;
  8. // 设置系统属性“java.awt.headless”的值,默认为 true
  9. configureHeadlessProperty();
  10. // 创建所有 Spring 运行监听器并发布应用启动事件,
  11. SpringApplicationRunListeners listeners = getRunListeners(args);
  12. listeners.starting(bootstrapContext, this.mainApplicationClass);
  13. try {
  14. // 初始化默认应用参数类
  15. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  16. // 根据运行监听器、引导上下文、应用参数来准备 Spring 环境
  17. ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  18. // 将要忽略的 bean 参数打开
  19. configureIgnoreBeanInfo(environment);
  20. // 创建并执行 banner 打印类
  21. Banner printedBanner = printBanner(environment);
  22. // 创建应用上下文
  23. context = createApplicationContext();
  24. // 设置应用程序启动 步骤
  25. context.setApplicationStartup(this.applicationStartup);
  26. // 准备应用上下文
  27. prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  28. // 刷新应用上下文
  29. refreshContext(context);
  30. // 刷新之后,空方法
  31. afterRefresh(context, applicationArguments);
  32. // 停止计时监控类
  33. stopWatch.stop();
  34. // 输出日志记录
  35. if (this.logStartupInfo) {
  36. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  37. }
  38. // 发布应用上下文启动监听事件
  39. listeners.started(context);
  40. // 执行所有的 Runner 运行器
  41. callRunners(context, applicationArguments);
  42. }
  43. catch (Throwable ex) {
  44. handleRunFailure(context, ex, listeners);
  45. throw new IllegalStateException(ex);
  46. }
  47. try {
  48. // 发布应用上下文就绪事件
  49. listeners.running(context);
  50. }
  51. catch (Throwable ex) {
  52. handleRunFailure(context, ex, null);
  53. throw new IllegalStateException(ex);
  54. }
  55. return context;
  56. }

创建并启动引导上下文,2.4.0 之后的版本增加的新功能

  1. private DefaultBootstrapContext createBootstrapContext() {
  2. DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
  3. this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));
  4. return bootstrapContext;
  5. }
  1. // 从 META-INF/spring.factories 中获取所有的配置类,并将其封装到 SpringApplicationRunListeners 对象中去,主要创建的对象为 EventPublishingRunListener
  2. private SpringApplicationRunListeners getRunListeners(String[] args) {
  3. Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
  4. return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
  5. }
  1. public EventPublishingRunListener(SpringApplication application, String[] args) {
  2. this.application = application;
  3. this.args = args;
  4. this.initialMulticaster = new SimpleApplicationEventMulticaster();
  5. for (ApplicationListener<?> listener : application.getListeners()) {
  6. this.initialMulticaster.addApplicationListener(listener);
  7. }
  8. }
  1. void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
  2. doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
  3. (step) -> {
  4. if (mainApplicationClass != null) {
  5. step.tag("mainApplicationClass", mainApplicationClass.getName());
  6. }
  7. });
  8. }
  1. // 广播事件
  2. public void starting(ConfigurableBootstrapContext bootstrapContext) {
  3. this.initialMulticaster
  4. .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
  5. }
  1. // applicationStartingEvent 是 SpringBoot 框架最早执行的监听器,在该监听器执行 started 方法时,会继续发布事件,主要是基于 Spring 的事件机制
  2. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  3. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  4. Executor executor = getTaskExecutor();
  5. for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  6. // 如果线程池为空,则同步发送事件,否则异步发送事件
  7. if (executor != null) {
  8. executor.execute(() -> invokeListener(listener, event));
  9. }
  10. else {
  11. invokeListener(listener, event);
  12. }
  13. }
  14. }
  1. // 返回与给定事件匹配的监听器
  2. protected Collection<ApplicationListener<?>> getApplicationListeners(
  3. ApplicationEvent event, ResolvableType eventType) {
  4. Object source = event.getSource();
  5. Class<?> sourceType = (source != null ? source.getClass() : null);
  6. ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
  7. // Potential new retriever to populate
  8. CachedListenerRetriever newRetriever = null;
  9. // Quick check for existing entry on ConcurrentHashMap
  10. CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
  11. if (existingRetriever == null) {
  12. // Caching a new ListenerRetriever if possible
  13. if (this.beanClassLoader == null ||
  14. (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
  15. (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
  16. newRetriever = new CachedListenerRetriever();
  17. existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
  18. if (existingRetriever != null) {
  19. newRetriever = null; // no need to populate it in retrieveApplicationListeners
  20. }
  21. }
  22. }
  23. if (existingRetriever != null) {
  24. Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
  25. if (result != null) {
  26. return result;
  27. }
  28. // If result is null, the existing retriever is not fully populated yet by another thread.
  29. // Proceed like caching wasn't possible for this current local attempt.
  30. }
  31. return retrieveApplicationListeners(eventType, sourceType, newRetriever);
  32. }

Source 继承自 SimpleCommandLinePropertySource,用于解析简单的命令行参数

  1. public DefaultApplicationArguments(String... args) {
  2. Assert.notNull(args, "Args must not be null");
  3. this.source = new Source(args);
  4. this.args = args;
  5. }
  1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
  2. DefaultBootstrapContext bootstrapContext, 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 环境准备,广播 ApplicationEnvironmentPreparedEvent
  10. listeners.environmentPrepared(bootstrapContext, environment);
  11. // 附加配置源
  12. DefaultPropertiesPropertySource.moveToEnd(environment);
  13. // 配置其他激活文件
  14. configureAdditionalProfiles(environment);
  15. // 将环境绑定给当前应用程序
  16. bindToSpringApplication(environment);
  17. if (!this.isCustomEnvironment) {
  18. environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
  19. }
  20. // 配置 propertySource 对它自己的递归依赖
  21. ConfigurationPropertySources.attach(environment);
  22. return environment;
  23. }

打印 banner 的详细操作过程

  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(null);
  7. SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
  8. if (this.bannerMode == Mode.LOG) {
  9. return bannerPrinter.print(environment, this.mainApplicationClass, logger);
  10. }
  11. return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
  12. }

根据不同的应用类型初始化不同的山下文应用类

  1. protected ConfigurableApplicationContext createApplicationContext() {
  2. return this.applicationContextFactory.create(this.webApplicationType);
  3. }
  1. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  2. // 设置应用上下文的 environment
  3. context.setEnvironment(environment);
  4. // 应用山下文的后置处理
  5. postProcessApplicationContext(context);
  6. // 为上下文应用所有初始化器,执行前面设置的 ApplicationContextInitializer 类
  7. applyInitializers(context);
  8. // 触发所有 SpringApplicationRunListener 监听器的 contextPrepared 事件方法。添加所有的事件监听器
  9. listeners.contextPrepared(context);
  10. bootstrapContext.close(context);
  11. // 记录启动日志
  12. if (this.logStartupInfo) {
  13. logStartupInfo(context.getParent() == null);
  14. logStartupProfileInfo(context);
  15. }
  16. // Add boot specific singleton beans
  17. // 注册启动参数bean,将容器指定的参数封装成bean,注入容器
  18. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  19. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  20. if (printedBanner != null) {
  21. beanFactory.registerSingleton("springBootBanner", printedBanner);
  22. }
  23. if (beanFactory instanceof DefaultListableBeanFactory) {
  24. ((DefaultListableBeanFactory) beanFactory)
  25. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  26. }
  27. if (this.lazyInitialization) {
  28. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  29. }
  30. // Load the sources
  31. // 加载所有资源
  32. Set<Object> sources = getAllSources();
  33. Assert.notEmpty(sources, "Sources must not be empty");
  34. // 将 bean 加载到上下文中
  35. load(context, sources.toArray(new Object[0]));
  36. // 触发所有 SpringApplicationRunListener 监听器的 contextLoaded 事件方法
  37. listeners.contextLoaded(context);
  38. }
  1. protected void load(ApplicationContext context, Object[] sources) {
  2. if (logger.isDebugEnabled()) {
  3. logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
  4. }
  5. BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
  6. if (this.beanNameGenerator != null) {
  7. loader.setBeanNameGenerator(this.beanNameGenerator);
  8. }
  9. if (this.resourceLoader != null) {
  10. loader.setResourceLoader(this.resourceLoader);
  11. }
  12. if (this.environment != null) {
  13. loader.setEnvironment(this.environment);
  14. }
  15. loader.load();
  16. }
  17. // 后续会使用其将主资源加载到上下文中去,供后续解析使用
  18. BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
  19. Assert.notNull(registry, "Registry must not be null");
  20. Assert.notEmpty(sources, "Sources must not be empty");
  21. this.sources = sources;
  22. this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
  23. this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
  24. this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
  25. this.scanner = new ClassPathBeanDefinitionScanner(registry);
  26. this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
  27. }
  1. void load() {
  2. for (Object source : this.sources) {
  3. load(source);
  4. }
  5. }
  6. private void load(Object source) {
  7. Assert.notNull(source, "Source must not be null");
  8. if (source instanceof Class<?>) {
  9. // Class 的方式加载
  10. load((Class<?>) source);
  11. return;
  12. }
  13. if (source instanceof Resource) {
  14. // Resource 资源的方式加载
  15. load((Resource) source);
  16. return;
  17. }
  18. if (source instanceof Package) {
  19. load((Package) source);
  20. return;
  21. }
  22. if (source instanceof CharSequence) {
  23. load((CharSequence) source);
  24. return;
  25. }
  26. throw new IllegalArgumentException("Invalid source type " + source.getClass());
  27. }
  28. private void load(Class<?> source) {
  29. if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
  30. // Any GroovyLoaders added in beans{} DSL can contribute beans here
  31. GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
  32. ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
  33. }
  34. if (isEligible(source)) {
  35. // 将符合条件的类注册到应用上下文
  36. this.annotatedReader.register(source);
  37. }
  38. }
  39. // 不是常规的闭包并且不是匿名类,即可
  40. private boolean isEligible(Class<?> type) {
  41. return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
  42. }

最终会调用到 AbstractApplicationContext 抽象类中的 refresh() 方法中去

  1. refreshContext(context);

空方法,用于扩展

执行所有 Runner 执行器,执行所有 ApplicationRunner 和 CommandLineRunner 两种运行器。

  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. }

版权声明:本文为ice-image原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ice-image/p/14549167.html