启动流程

图如下:

以上流程图源文件(可导入https://www.processon.com):https://github.com/Mysakura/DataFiles

相关Event(org.springframework.boot.context.event.SpringApplicationEvent的子类),这些Event是很好的标志,告诉我们程序执行到哪一步了,如下

ApplicationStartingEvent:在Environment和ApplicationContext可用之前 & 在ApplicationListener注册之后发布。
ApplicationContextInitializedEvent:在bean定义加载之前 & ApplicationContextInitializers被调用之后 & ApplicationContext开始准备之后发布
ApplicationPreparedEvent:在ApplicationContext完全准备好并且没有刷新之前发布,此时bean定义即将加载,Environment已经准备好被使用。
ApplicationStartedEvent:在ApplicationContext刷新之后,调用ApplicationRunner和CommandLineRunner之前发布
ApplicationReadyEvent:应用已经准备好接受请求时发布。

第一步,先进入启动类

  1. @SpringBootApplication
  2. public class DemoApplication {
  3.  
  4. public static void main(String[] args) {
  5. SpringApplication.run(DemoApplication.class, args);
  6. }
  7.  
  8. }

第二步,执行run方法,实际上执行的是【org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])】

  1. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  2. return run(new Class<?>[] { primarySource }, args);
  3. }
  4.  
  5. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  6. // 初始化SpringApplication,然后执行run方法
  7. return new SpringApplication(primarySources).run(args);
  8. }

1. new SpringApplication【org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)】

  1. public SpringApplication(Class<?>... primarySources) {
  2. this(null, primarySources);
  3. }
  4.  
  5. // 初始化一些成员变量:
  6. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  7. this.resourceLoader = resourceLoader;
  8. Assert.notNull(primarySources, "PrimarySources must not be null");
  9. // 初始化primarySources
  10. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  11. // 判断当前应用是一个基于Servlet或者reactive的web应用还是一个非web应用
  12. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  13. // 初始化一系列ApplicationContextInitializer
  14. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  15. // 初始化一系列ApplicationListener,这些是针对SpringBoot事件的监听器
  16. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  17. // 配置主要应用启动类
  18. this.mainApplicationClass = deduceMainApplicationClass();
  19. }

2. run【org.springframework.boot.SpringApplication#run(java.lang.String...)】

  1. public ConfigurableApplicationContext run(String... args) {
  2. // 一个计算耗时小工具:A
  3. StopWatch stopWatch = new StopWatch();
  4. stopWatch.start();
  5. ConfigurableApplicationContext context = null;
  6. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  7. configureHeadlessProperty();
  8. // 获取监听器,SpringApplicationRunListener的作用是发布SpringBoot运行期间的事件:B
  9. SpringApplicationRunListeners listeners = getRunListeners(args);
  10. // 监听器发布事件:C
  11. listeners.starting();
  12. try {
  13. // 创建默认应用参数
  14. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  15. // 准备环境:D
  16. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  17. // 处理要忽略的bean信息
  18. configureIgnoreBeanInfo(environment);
  19. // 打印Banner
  20. Banner printedBanner = printBanner(environment);
  21. // 获取应用上下文:E
  22. context = createApplicationContext();
  23. // 获取异常报告实例列表
  24. exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
  25. new Class[] { ConfigurableApplicationContext.class }, context);
  26. // 准备上下文:F
  27. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  28. // 刷新上下文:G
  29. refreshContext(context);
  30. // 留给子类实现,在刷新之后做一下额外的处理
  31. afterRefresh(context, applicationArguments);
  32. // 计时器计时完毕
  33. stopWatch.stop();
  34. if (this.logStartupInfo) {
  35. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  36. }
  37. // 发布ApplicationStartedEvent事件:H
  38. listeners.started(context);
  39. // 调用Runners:I
  40. callRunners(context, applicationArguments);
  41. }
  42. catch (Throwable ex) {
  43. handleRunFailure(context, ex, exceptionReporters, listeners);
  44. throw new IllegalStateException(ex);
  45. }
  46.  
  47. try {
  48. // 发布ApplicationReadyEvent事件:J
  49. listeners.running(context);
  50. }
  51. catch (Throwable ex) {
  52. handleRunFailure(context, ex, exceptionReporters, null);
  53. throw new IllegalStateException(ex);
  54. }
  55. return context;
  56. }

A:计算耗时小工具(运行如下测试代码)

  1. StopWatch stopWatch = new StopWatch("Test ABC");
  2. stopWatch.start("Task A");
  3. for (int i = 0; i < 10; i++){ }
  4. stopWatch.stop();
  5. stopWatch.start("Task B");
  6. for (int i = 0; i < 5; i++){ }
  7. stopWatch.stop();
  8. stopWatch.start("Task C");
  9. for (int i = 0; i < 15; i++){ }
  10. stopWatch.stop();
  11. System.out.println(stopWatch.prettyPrint());

输出:

B: 获取监听器*

  1. private SpringApplicationRunListeners getRunListeners(String[] args) {
  2. Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
  3. // 返回一个SpringApplicationRunListener的集合包装类
  4. return new SpringApplicationRunListeners(logger,
  5. getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
  6. }
  7.  
  8. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  9. ClassLoader classLoader = getClassLoader();
  10. // 使用Set集合确保name是唯一的;调用SpringFactoriesLoader.loadFactoryNames,使用给定的类加载器加载给定类型工厂实现的完全限定类名
  11. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  12. // 根据给的Class、类加载器、完全限定类型列表已经相关参数,根据反射创建实例列表
  13. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  14. AnnotationAwareOrderComparator.sort(instances);
  15. return instances;
  16. }
  17.  
  18. @SuppressWarnings("unchecked")
  19. private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
  20. ClassLoader classLoader, Object[] args, Set<String> names) {
  21. List<T> instances = new ArrayList<>(names.size());
  22. for (String name : names) {
  23. try {
  24. Class<?> instanceClass = ClassUtils.forName(name, classLoader);
  25. Assert.isAssignable(type, instanceClass);
  26. Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
  27. T instance = (T) BeanUtils.instantiateClass(constructor, args);
  28. instances.add(instance);
  29. }
  30. catch (Throwable ex) {
  31. throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
  32. }
  33. }
  34. return instances;
  35. }

C:发布【ApplicationStartingEvent】事件

  1. public void starting() {
  2. this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
  3. }

D:准备环境*

  1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
  2. ApplicationArguments applicationArguments) {
  3. // 根据webApplicationType,决定创建StandardServletEnvironment还是StandardReactiveWebEnvironment还是StandardEnvironment
  4. ConfigurableEnvironment environment = getOrCreateEnvironment();
  5. // 配置属性文件和激活的环境(spring.profiles.active所配)
  6. configureEnvironment(environment, applicationArguments.getSourceArgs());
  7. // 将ConfigurationPropertySource附加到指定环境下
  8. ConfigurationPropertySources.attach(environment);
  9. // 发布ApplicationEnvironmentPreparedEvent事件
  10. listeners.environmentPrepared(environment);
  11. // 绑定环境到应用
  12. bindToSpringApplication(environment);
  13. if (!this.isCustomEnvironment) {
  14. environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
  15. deduceEnvironmentClass());
  16. }
  17. ConfigurationPropertySources.attach(environment);
  18. return environment;
  19. }

E:获取应用上下文

  1. // 根据应用类型创建不同的上下文
  2. protected ConfigurableApplicationContext createApplicationContext() {
  3. Class<?> contextClass = this.applicationContextClass;
  4. if (contextClass == null) {
  5. try {
  6. switch (this.webApplicationType) {
  7. case SERVLET:
  8. contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
  9. break;
  10. case REACTIVE:
  11. contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
  12. break;
  13. default:
  14. contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
  15. }
  16. }
  17. catch (ClassNotFoundException ex) {
  18. throw new IllegalStateException(
  19. "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
  20. }
  21. }
  22. return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
  23. }

F:准备上下文*

  1. private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
  2. SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
  3. // 设置environment
  4. context.setEnvironment(environment);
  5. // 相关额外的处理
  6. postProcessApplicationContext(context);
  7. applyInitializers(context);
  8. // 派发ApplicationContextInitializedEvent事件,表示应用正在启动,上下文正在准备并且一系列Initializer已经调用
  9. listeners.contextPrepared(context);
  10. if (this.logStartupInfo) {
  11. logStartupInfo(context.getParent() == null);
  12. logStartupProfileInfo(context);
  13. }
  14. // Add boot specific singleton beans
  15. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  16. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  17. if (printedBanner != null) {
  18. beanFactory.registerSingleton("springBootBanner", printedBanner);
  19. }
  20. if (beanFactory instanceof DefaultListableBeanFactory) {
  21. ((DefaultListableBeanFactory) beanFactory)
  22. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  23. }
  24. if (this.lazyInitialization) {
  25. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  26. }
  27. // Load the sources
  28. Set<Object> sources = getAllSources();
  29. Assert.notEmpty(sources, "Sources must not be empty");
  30. load(context, sources.toArray(new Object[0]));
  31. // 监听上下文,派发ApplicationPreparedEvent事件,表示应用正在启动,上下文已经准备好刷新了
  32. listeners.contextLoaded(context);
  33. }
  34.  
  35. protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
  36. if (this.beanNameGenerator != null) {
  37. // 注册注解工具类
  38. context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
  39. this.beanNameGenerator);
  40. }
  41. if (this.resourceLoader != null) {
  42. if (context instanceof GenericApplicationContext) {
  43. // 设置resourceLoader
  44. ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
  45. }
  46. if (context instanceof DefaultResourceLoader) {
  47. ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
  48. }
  49. }
  50. if (this.addConversionService) {
  51. // 设置ConversionService
  52. context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
  53. }
  54. }

G:刷新上下文(容器的初始化)【org.springframework.context.support.AbstractApplicationContext#refresh】*

  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. }
  12.  
  13. protected void refresh(ApplicationContext applicationContext) {
  14. Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
  15. ((AbstractApplicationContext) applicationContext).refresh();
  16. }
  17.  
  18. public void refresh() throws BeansException, IllegalStateException {
  19. synchronized (this.startupShutdownMonitor) {
  20. // Prepare this context for refreshing.
  21. // 为上下文刷新做准备
  22. prepareRefresh();
  23.  
  24. // Tell the subclass to refresh the internal bean factory.
  25. // 告诉子类刷新内部bean工厂
  26. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  27.  
  28. // Prepare the bean factory for use in this context.
  29. // 准备在这个上下文要用的bean工厂
  30. prepareBeanFactory(beanFactory);
  31.  
  32. try {
  33. // Allows post-processing of the bean factory in context subclasses.
  34. // 允许在上下文子类中对bean工厂进行后续处理
  35. postProcessBeanFactory(beanFactory);
  36.  
  37. // Invoke factory processors registered as beans in the context.
  38. // 执行上下文中已注册的bean工厂后置处理器
  39. invokeBeanFactoryPostProcessors(beanFactory);
  40.  
  41. // Register bean processors that intercept bean creation.
  42. // 注册拦截bean创建过程的后置处理器
  43. registerBeanPostProcessors(beanFactory);
  44.  
  45. // Initialize message source for this context.
  46. // 初始化此上下文的消息源
  47. initMessageSource();
  48.  
  49. // Initialize event multicaster for this context.
  50. // 初始化事件派发器
  51. initApplicationEventMulticaster();
  52.  
  53. // Initialize other special beans in specific context subclasses.
  54. // 初始化子类实现的其它特殊bean
  55. onRefresh();
  56.  
  57. // Check for listener beans and register them.
  58. // 检查并注册侦听器bean
  59. registerListeners();
  60.  
  61. // Instantiate all remaining (non-lazy-init) singletons.
  62. // 实例化所有剩余的(非延迟初始化)单实例bean
  63. finishBeanFactoryInitialization(beanFactory);
  64.  
  65. // Last step: publish corresponding event.
  66. // 最后,发布对应的事件
  67. finishRefresh();
  68. }
  69.  
  70. catch (BeansException ex) {
  71. if (logger.isWarnEnabled()) {
  72. logger.warn("Exception encountered during context initialization - " +
  73. "cancelling refresh attempt: " + ex);
  74. }
  75.  
  76. // Destroy already created singletons to avoid dangling resources.
  77. destroyBeans();
  78.  
  79. // Reset 'active' flag.
  80. cancelRefresh(ex);
  81.  
  82. // Propagate exception to caller.
  83. throw ex;
  84. }
  85.  
  86. finally {
  87. // Reset common introspection caches in Spring's core, since we
  88. // might not ever need metadata for singleton beans anymore...
  89. resetCommonCaches();
  90. }
  91. }
  92. }

H:发布ApplicationStartedEvent事件(listeners.started(context);)【org.springframework.boot.context.event.EventPublishingRunListener#started】

  1. public void started(ConfigurableApplicationContext context) {
  2. context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
  3. }

I:调用Runners

  1. private void callRunners(ApplicationContext context, ApplicationArguments args) {
  2. List<Object> runners = new ArrayList<>();
  3. // 获取所有实现ApplicationRunner接口的子类
  4. runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  5. // 获取所有实现CommandLineRunner接口的子类
  6. runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  7. AnnotationAwareOrderComparator.sort(runners);
  8. // 循环遍历
  9. for (Object runner : new LinkedHashSet<>(runners)) {
  10. // 如果是ApplicationRunner的实现类
  11. if (runner instanceof ApplicationRunner) {
  12. callRunner((ApplicationRunner) runner, args);
  13. }
  14. // 如果是CommandLineRunner的实现类
  15. if (runner instanceof CommandLineRunner) {
  16. callRunner((CommandLineRunner) runner, args);
  17. }
  18. }
  19. }
  20.  
  21. private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
  22. try {
  23. (runner).run(args);
  24. }
  25. catch (Exception ex) {
  26. throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
  27. }
  28. }
  29.  
  30. private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
  31. try {
  32. (runner).run(args.getSourceArgs());
  33. }
  34. catch (Exception ex) {
  35. throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
  36. }
  37. }

那么这两个类有啥作用呢

首先,SpringBoot并没有默认的实现类,那么肯定是给我们实现的;然后这个方法的执行时机是在spring容器启动完毕的时候,那么作用肯定是在容器启动之后做一些其它自定义的处理。

这两个接口都只有一个方法,就是run方法。类注解上写的说明:

当SpringApplication中包含了该接口的实现类,在callRunners的时候调用其中的run方法;可以在同一个应用上下文定义多个bean,也可以通过实现Order接口或者使用@Order注解来排序。

这两个类的唯一区别就是run方法的参数类型不同:

org.springframework.boot.CommandLineRunner#run(String... args)

org.springframework.boot.ApplicationRunner#run(ApplicationArguments args)

J:发布ApplicationReadyEvent事件(listeners.running(context);)【org.springframework.boot.context.event.EventPublishingRunListener#running】

  1. public void running(ConfigurableApplicationContext context) {
  2. context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
  3. }

到此一个大概的流程已经走完,而我还想看一下具体的东西。

--------------------------------------------------------------------------------------------------------------------------------------------------------

进一步深入

问题0:我看有好几个地方都用到了同一个方法:org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)

  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  2. ClassLoader classLoader = getClassLoader();
  3. // 加载工程名称列表,通过Set集合保证唯一①
  4. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  5. // 根据名称,创建相关实例②
  6. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  7. // 排序后返回
  8. AnnotationAwareOrderComparator.sort(instances);
  9. return instances;
  10. }

来看①

  1. public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  2. String factoryTypeName = factoryType.getName();
  3. return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
  4. }
  5.  
  6. private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  7. // 查看缓存有么有
  8. MultiValueMap<String, String> result = cache.get(classLoader);
  9. if (result != null) {
  10. return result;
  11. }
  12.  
  13. try {
  14. // 获取spring.factories资源路径
  15. Enumeration<URL> urls = (classLoader != null ?
  16. classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
  17. ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
  18. result = new LinkedMultiValueMap<>();
  19. while (urls.hasMoreElements()) {
  20. URL url = urls.nextElement();
  21. UrlResource resource = new UrlResource(url);
  22. // 加载资源
  23. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  24. for (Map.Entry<?, ?> entry : properties.entrySet()) {
  25. String factoryTypeName = ((String) entry.getKey()).trim();
  26. for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
  27. // key为工厂类型接口名称,值为一系列子类实现
  28. result.add(factoryTypeName, factoryImplementationName.trim());
  29. }
  30. }
  31. }
  32. // 放入缓存并返回
  33. cache.put(classLoader, result);
  34. return result;
  35. }
  36. catch (IOException ex) {
  37. throw new IllegalArgumentException("Unable to load factories from location [" +
  38. FACTORIES_RESOURCE_LOCATION + "]", ex);
  39. }
  40. }

具体来看SpringBoot的spring.factories里面的内容:是一系列的组件以及具体的实现列表

通过把这些配置事先读取并放进缓存,我们就可以随时根据工厂接口类型获取对应的子类名称列表。

再来看②

  1. private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
  2. ClassLoader classLoader, Object[] args, Set<String> names) {
  3. List<T> instances = new ArrayList<>(names.size());
  4. // 遍历子类名称,通过反射进行实例化
  5. for (String name : names) {
  6. try {
  7. Class<?> instanceClass = ClassUtils.forName(name, classLoader);
  8. Assert.isAssignable(type, instanceClass);
  9. Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
  10. T instance = (T) BeanUtils.instantiateClass(constructor, args);
  11. instances.add(instance);
  12. }
  13. catch (Throwable ex) {
  14. throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
  15. }
  16. }
  17. return instances;
  18. }

一句话作用:这个方法的作用就是找到spring.factories读取一系列组件的名称,通过传入的Class类型获取对应的子类名称列表进行实例化并返回。

问题1:那一系列Initializer都有哪些,有什么作用【setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

0:报告常见的错误配置警告

1:配置ApplicationContext ID

2:执行环境属性【context.initializer.classes】指定的初始化器,也就是给用户一个机会去指定自己实现的ApplicationContextInitializer从而对应用程序做一些初始化工作

3:将RSocketServer实际监听的端口写入Environment环境属性中。这样属性local.rsocket.server.port就可以直接通过@Value注入到测试中,或者通过Environment获取。

4:将WebServer实际监听的端口写入Environment环境属性中。这样属性local.server.port就可以直接通过@Value注入到测试中,或者通过Environment获取。

5:创建一个ConfigurationClassPostProcessor 和 Spring Boot共用的CachingMetadataReaderFactory对象

6:将ConditionEvaluationReport写入日志。

问题2:那一系列Listeners有哪些,有什么作用【setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));】

0:一旦装载了上下文,就清空缓存。

1:在其父应用程序上下文关闭时关闭该应用程序上下文

2:如果系统文件编码与environment里设置的不一致,则停止启动应用程序。默认情况下么有影响,别手贱乱设置。

3:根据属性{spring.output.ansi.enabled}的值配置{AnsiOutput}

4:通过读取已知位置属性文件里的属性来配置上下文的environment,默认加载application.properties或者application.yml里的配置。

5:执行配置在context.listener.classes环境变量里的Listener

6:通过在{DEBUG}级别记录线程上下文类加载器(TCCL)的类路径来对ApplicationEnvironmentPreparedEvent和ApplicationFailedEvent事件做出反应

7:一个配置{LoggingSystem}的ApplicationListener。如果环境包含{logging.config}属性,它将用于引导日志系统,否则将使用默认配置。无论如何,如果环境包含{logging.level},那么日志级别将被定制。

8:将liquibase {ServiceLocator}替换成和SpringBoot可执行归档一起工作的版本。

9:在耗时任务的后台线程中触发早期初始化

问题3:SpringApplicationRunListeners listeners = getRunListeners(args);怎么又出来一个listeners?

  1. private SpringApplicationRunListeners getRunListeners(String[] args) {
  2. Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
  3. // 可以看出,通过getSpringFactoriesInstances读取对应的names并实例化返回,然后封装在SpringApplicationRunListeners
  4. return new SpringApplicationRunListeners(logger,
  5. getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
  6. }

在这里实例化的是:

问题4:listeners.starting();是启动监听器吗?

  1. void starting() {
  2. // 遍历内部的listener,执行starting方法
  3. for (SpringApplicationRunListener listener : this.listeners) {
  4. listener.starting();
  5. }
  6. }
  7.  
  8. // starting方法,实际上是广播ApplicationStartingEvent事件
  9. public void starting() {
  10. this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
  11. }

广播事件,有哪些收听者呢?

  1. public void multicastEvent(ApplicationEvent event) {
  2. multicastEvent(event, resolveDefaultEventType(event));
  3. }
  4.  
  5. @Override
  6. public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
  7. ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
  8. Executor executor = getTaskExecutor();
  9. // 典型的观察者模式
  10. for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
  11. if (executor != null) {
  12. executor.execute(() -> invokeListener(listener, event));
  13. }
  14. else {
  15. invokeListener(listener, event);
  16. }
  17. }
  18. }

收听者就是我们之前第一步实例化的listener

问题5:Bean在哪里实例化的

先创建bean定义

  1. 进入org.springframework.boot.SpringApplication#run(java.lang.String...)
  2. 进入refreshContext(context);方法
  3. 最终进入org.springframework.context.support.AbstractApplicationContext#refresh
  4. 进入invokeBeanFactoryPostProcessors(beanFactory);
  5. 进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  6. 进入invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  7. 里面是一个循环,进入postProcessor.postProcessBeanDefinitionRegistry(registry);
  8. 进入processConfigBeanDefinitions(registry);
  9. 进入parser.parse(candidates);
  10. 里面是一个遍历BeanDefinitionHolder的过程,获取BeanDefinition。根据BeanDefinition实现的接口执行不同的方法,但是最终都进入org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
  11. 进入sourceClass = doProcessConfigurationClass(configClass, sourceClass);

到此慢慢接近了真相

  1. protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
  2. throws IOException {
  3.  
  4. if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
  5. // Recursively process any member (nested) classes first
  6. processMemberClasses(configClass, sourceClass);
  7. }
  8.  
  9. // 处理@PropertySource标记的类
  10. for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
  11. sourceClass.getMetadata(), PropertySources.class,
  12. org.springframework.context.annotation.PropertySource.class)) {
  13. if (this.environment instanceof ConfigurableEnvironment) {
  14. processPropertySource(propertySource);
  15. }
  16. else {
  17. logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
  18. "]. Reason: Environment must implement ConfigurableEnvironment");
  19. }
  20. }
  21.  
  22. // 处理@ComponentScan标记的类
  23. Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
  24. sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
  25. if (!componentScans.isEmpty() &&
  26. !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
  27. for (AnnotationAttributes componentScan : componentScans) {
  28. // 立即执行扫描 A
  29. Set<BeanDefinitionHolder> scannedBeanDefinitions =
  30. this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
  31. // 检查已扫描的定义集合以获得更多的配置类,并在需要时进行递归解析
  32. for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
  33. BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
  34. if (bdCand == null) {
  35. bdCand = holder.getBeanDefinition();
  36. }
  37. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
  38. parse(bdCand.getBeanClassName(), holder.getBeanName());
  39. }
  40. }
  41. }
  42. }
  43.  
  44. // 处理@Import标记的类
  45. processImports(configClass, sourceClass, getImports(sourceClass), true);
  46.  
  47. // 处理@ImportResource标记的类
  48. AnnotationAttributes importResource =
  49. AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
  50. if (importResource != null) {
  51. String[] resources = importResource.getStringArray("locations");
  52. Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
  53. for (String resource : resources) {
  54. String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
  55. configClass.addImportedResource(resolvedResource, readerClass);
  56. }
  57. }
  58.  
  59. // 处理单个@Bean标记的方法
  60. Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
  61. for (MethodMetadata methodMetadata : beanMethods) {
  62. configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
  63. }
  64.  
  65. // 处理接口里的默认方法
  66. processInterfaces(configClass, sourceClass);
  67.  
  68. // 处理父类, 如果有的话
  69. if (sourceClass.getMetadata().hasSuperClass()) {
  70. String superclass = sourceClass.getMetadata().getSuperClassName();
  71. if (superclass != null && !superclass.startsWith("java") &&
  72. !this.knownSuperclasses.containsKey(superclass)) {
  73. this.knownSuperclasses.put(superclass, configClass);
  74. // Superclass found, return its annotation metadata and recurse
  75. return sourceClass.getSuperClass();
  76. }
  77. }
  78.  
  79. // 没有父类,处理完成
  80. return null;
  81. }

我们来看一下扫描过程,进入注释A的那段代码:this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());

这个方法主要读取相关的属性,最后的方法是处理过程。其中一段代码,判断basePackages是否为空,如果为空,则默认扫描启动类所在的包

现在进入最后的doScan方法。

  1. protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
  2. Assert.notEmpty(basePackages, "At least one base package must be specified");
  3. Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
  4. for (String basePackage : basePackages) {
  5. // 具体扫描包,组装成BeanDefinition返回
  6. Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
  7. for (BeanDefinition candidate : candidates) {
  8. ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
  9. candidate.setScope(scopeMetadata.getScopeName());
  10. String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
  11. if (candidate instanceof AbstractBeanDefinition) {
  12. postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
  13. }
  14. if (candidate instanceof AnnotatedBeanDefinition) {
  15. AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
  16. }
  17. if (checkCandidate(beanName, candidate)) {
  18. BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
  19. definitionHolder =
  20. AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
  21. beanDefinitions.add(definitionHolder);
  22. // 注册bean定义,也就是注册到beanFactory里(this.registry的类型是org.springframework.beans.factory.support.DefaultListableBeanFactory)
  23. registerBeanDefinition(definitionHolder, this.registry);
  24. }
  25. }
  26. }
  27. return beanDefinitions;
  28. }

进入注册bean的方法(最终进入org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition

  1. public static void registerBeanDefinition(
  2. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
  3. throws BeanDefinitionStoreException {
  4.  
  5. // 在主名称下注册bean定义
  6. String beanName = definitionHolder.getBeanName();
  7. // 具体注册方法
  8. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
  9.  
  10. // 如果有的话,为bean名称注册别名
  11. String[] aliases = definitionHolder.getAliases();
  12. if (aliases != null) {
  13. for (String alias : aliases) {
  14. registry.registerAlias(beanName, alias);
  15. }
  16. }
  17. }

进入具体注册方法(org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition

实际上是把bean定义放进了一个Map里面。到此为止,bean定义已经注册到beanFactory里了。但是这个时候还没有实例化,仅仅是拿到了bean定义。

实例化

刚才我们走的是invokeBeanFactoryPostProcessors(beanFactory);,现在走 finishBeanFactoryInitialization(beanFactory);

  1. protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
  2. // 为上下文初始化conversion service
  3. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
  4. beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
  5. beanFactory.setConversionService(
  6. beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
  7. }
  8.  
  9. // 如果之前没有任何bean后置处理器(例如PropertyPlaceholderConfigurer bean)注册,则注册一个默认的嵌入式值解析器
  10. // 此时,主要用于解析注解属性值。
  11. if (!beanFactory.hasEmbeddedValueResolver()) {
  12. beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
  13. }
  14.  
  15. // 尽早初始化LoadTimeWeaverAware bean,以便尽早注册它们的转换器
  16. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
  17. for (String weaverAwareName : weaverAwareNames) {
  18. getBean(weaverAwareName);
  19. }
  20.  
  21. // 停止使用临时类加载器进行类型匹配。
  22. beanFactory.setTempClassLoader(null);
  23.  
  24. // 允许缓存所有的bean定义元数据,不希望有进一步的更改。
  25. beanFactory.freezeConfiguration();
  26.  
  27. // 实例化所有剩余的(非懒加载)单例。
  28. beanFactory.preInstantiateSingletons();
  29. }

进入最后一行

  1. public void preInstantiateSingletons() throws BeansException {
  2. if (logger.isTraceEnabled()) {
  3. logger.trace("Pre-instantiating singletons in " + this);
  4. }
  5.  
  6. // 遍历一个副本以允许init方法,而init方法反过来注册新的bean定义。
  7. // 虽然这可能不是常规的工厂引导的一部分,但它在其他方面也可以正常工作。
  8. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
  9.  
  10. // 触发所有非懒加载bean的初始化
  11. for (String beanName : beanNames) {
  12. RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
  13. if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
  14. if (isFactoryBean(beanName)) {
  15. Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
  16. if (bean instanceof FactoryBean) {
  17. final FactoryBean<?> factory = (FactoryBean<?>) bean;
  18. boolean isEagerInit;
  19. if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
  20. isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
  21. ((SmartFactoryBean<?>) factory)::isEagerInit,
  22. getAccessControlContext());
  23. }
  24. else {
  25. isEagerInit = (factory instanceof SmartFactoryBean &&
  26. ((SmartFactoryBean<?>) factory).isEagerInit());
  27. }
  28. if (isEagerInit) {
  29. getBean(beanName);
  30. }
  31. }
  32. }
  33. else {
  34. // 实例化bean,实际进入的是org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法,里面包含了具体实例化的过程
  35. getBean(beanName);
  36. }
  37. }
  38. }
  39.  
  40. // 为所有适用的bean触发初始化后回调
  41. for (String beanName : beanNames) {
  42. Object singletonInstance = getSingleton(beanName);
  43. if (singletonInstance instanceof SmartInitializingSingleton) {
  44. final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
  45. if (System.getSecurityManager() != null) {
  46. AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  47. smartSingleton.afterSingletonsInstantiated();
  48. return null;
  49. }, getAccessControlContext());
  50. }
  51. else {
  52. smartSingleton.afterSingletonsInstantiated();
  53. }
  54. }
  55. }
  56. }

最后看一下具体实例化的过程【org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

  1. // Create bean instance.
  2. if (mbd.isSingleton()) {
  3. sharedInstance = getSingleton(beanName, () -> {
  4. try {
  5. return createBean(beanName, mbd, args);
  6. }
  7. catch (BeansException ex) {
  8. // Explicitly remove instance from singleton cache: It might have been put there
  9. // eagerly by the creation process, to allow for circular reference resolution.
  10. // Also remove any beans that received a temporary reference to the bean.
  11. destroySingleton(beanName);
  12. throw ex;
  13. }
  14. });
  15. bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
  16. }

进入createBean【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])】

  1. try {
  2. Object beanInstance = doCreateBean(beanName, mbdToUse, args);
  3. if (logger.isTraceEnabled()) {
  4. logger.trace("Finished creating instance of bean '" + beanName + "'");
  5. }
  6. return beanInstance;
  7. }
  8. catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
  9. // A previously detected exception with proper bean creation context already,
  10. // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
  11. throw ex;
  12. }
  13. catch (Throwable ex) {
  14. throw new BeanCreationException(
  15. mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
  16. }

进入doCreateBean【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

  1. // spring把实例化的类都放在了包装类里
  2. BeanWrapper instanceWrapper = null;
  3. if (mbd.isSingleton()) {
  4. instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
  5. }
  6. if (instanceWrapper == null) {
  7. instanceWrapper = createBeanInstance(beanName, mbd, args);
  8. }
  9. final Object bean = instanceWrapper.getWrappedInstance();
  10. Class<?> beanType = instanceWrapper.getWrappedClass();
  11. if (beanType != NullBean.class) {
  12. mbd.resolvedTargetType = beanType;
  13. }

进入createBeanInstance【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance

  1. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
  2. // 确保此时bean类已经被解析。
  3. Class<?> beanClass = resolveBeanClass(mbd, beanName);
  4.  
  5. if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
  6. throw new BeanCreationException(mbd.getResourceDescription(), beanName,
  7. "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
  8. }
  9.  
  10. Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
  11. if (instanceSupplier != null) {
  12. return obtainFromSupplier(instanceSupplier, beanName);
  13. }
  14.  
  15. if (mbd.getFactoryMethodName() != null) {
  16. return instantiateUsingFactoryMethod(beanName, mbd, args);
  17. }
  18.  
  19. // Shortcut when re-creating the same bean...
  20. boolean resolved = false;
  21. boolean autowireNecessary = false;
  22. if (args == null) {
  23. synchronized (mbd.constructorArgumentLock) {
  24. if (mbd.resolvedConstructorOrFactoryMethod != null) {
  25. resolved = true;
  26. autowireNecessary = mbd.constructorArgumentsResolved;
  27. }
  28. }
  29. }
  30. if (resolved) {
  31. if (autowireNecessary) {
  32. return autowireConstructor(beanName, mbd, null, null);
  33. }
  34. else {
  35. return instantiateBean(beanName, mbd);
  36. }
  37. }
  38.  
  39. // 为自动装配准备的候选构造函数
  40. Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  41. if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
  42. mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
  43. return autowireConstructor(beanName, mbd, ctors, args);
  44. }
  45.  
  46. // 为默认构造函数准备的首选构造函数
  47. ctors = mbd.getPreferredConstructors();
  48. if (ctors != null) {
  49. return autowireConstructor(beanName, mbd, ctors, null);
  50. }
  51.  
  52. // 不需要特殊处理:只需使用无参构造函数。
  53. return instantiateBean(beanName, mbd);
  54. }

因为本例只有一个Controller,所以运行到了最后一行:

进入instantiateBean【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean

  1. protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
  2. try {
  3. Object beanInstance;
  4. final BeanFactory parent = this;
  5. if (System.getSecurityManager() != null) {
  6. beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
  7. getInstantiationStrategy().instantiate(mbd, beanName, parent),
  8. getAccessControlContext());
  9. }
  10. else {
  11. // 获取instantiationStrategy策略,并调用instanttiate方法进行实例化
  12. beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
  13. }
  14. // 包装
  15. BeanWrapper bw = new BeanWrapperImpl(beanInstance);
  16. initBeanWrapper(bw);
  17. return bw;
  18. }
  19. catch (Throwable ex) {
  20. throw new BeanCreationException(
  21. mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
  22. }
  23. }

进入instantiate【org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)】

  1. public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
  2. // Don't override the class with CGLIB if no overrides.
  3. if (!bd.hasMethodOverrides()) {
  4. Constructor<?> constructorToUse;
  5. synchronized (bd.constructorArgumentLock) {
  6. constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
  7. if (constructorToUse == null) {
  8. // 获取Class
  9. final Class<?> clazz = bd.getBeanClass();
  10. if (clazz.isInterface()) {
  11. throw new BeanInstantiationException(clazz, "Specified class is an interface");
  12. }
  13. try {
  14. if (System.getSecurityManager() != null) {
  15. constructorToUse = AccessController.doPrivileged(
  16. (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
  17. }
  18. else {
  19. // 获取已声明的构造方法
  20. constructorToUse = clazz.getDeclaredConstructor();
  21. }
  22. bd.resolvedConstructorOrFactoryMethod = constructorToUse;
  23. }
  24. catch (Throwable ex) {
  25. throw new BeanInstantiationException(clazz, "No default constructor found", ex);
  26. }
  27. }
  28. }
  29. // 通过工具类实例化
  30. return BeanUtils.instantiateClass(constructorToUse);
  31. }
  32. else {
  33. // Must generate CGLIB subclass.
  34. return instantiateWithMethodInjection(bd, beanName, owner);
  35. }
  36. }

最后一步,看下如何实例化的【org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor<T>, java.lang.Object...)】

  1. public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
  2. Assert.notNull(ctor, "Constructor must not be null");
  3. try {
  4. // 反射工具类:使构造方法可访问
  5. ReflectionUtils.makeAccessible(ctor);
  6. if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
  7. return KotlinDelegate.instantiateClass(ctor, args);
  8. }
  9. else {
  10. // 获取参数类型列表
  11. Class<?>[] parameterTypes = ctor.getParameterTypes();
  12. Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
  13. Object[] argsWithDefaultValues = new Object[args.length];
  14. for (int i = 0 ; i < args.length; i++) {
  15. if (args[i] == null) {
  16. Class<?> parameterType = parameterTypes[i];
  17. argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
  18. }
  19. else {
  20. argsWithDefaultValues[i] = args[i];
  21. }
  22. }
  23. // 很熟悉的反射代码【java.lang.reflect.Constructor#newInstance】
  24. return ctor.newInstance(argsWithDefaultValues);
  25. }
  26. }
  27. catch (InstantiationException ex) {
  28. throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
  29. }
  30. catch (IllegalAccessException ex) {
  31. throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
  32. }
  33. catch (IllegalArgumentException ex) {
  34. throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
  35. }
  36. catch (InvocationTargetException ex) {
  37. throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
  38. }
  39. }

总结:

  1. // 在刷新上下文方法里
  2. org.springframework.context.support.AbstractApplicationContext#refresh
  3. // 获取并注册bean定义(包含了注解扫描等过程)
  4. postProcessBeanFactory(beanFactory);
  5. // 实例化所有非懒加载的bean(本质用了反射实现了实例化bean)
  6. finishBeanFactoryInitialization(beanFactory);

【源码阅读】SpringBoot-v2.2.0启动过程以及细节的更多相关文章

  1. Netty源码阅读(一) ServerBootstrap启动

    Netty源码阅读(一) ServerBootstrap启动 转自我的Github Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速 ...

  2. 曹工说Redis源码(3)-- redis server 启动过程完整解析(中)

    文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...

  3. 曹工说Redis源码(5)-- redis server 启动过程解析,以及EventLoop每次处理事件前的前置工作解析(下)

    曹工说Redis源码(5)-- redis server 启动过程解析,eventLoop处理事件前的准备工作(下) 文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis ...

  4. [源码分析] 消息队列 Kombu 之 启动过程

    [源码分析] 消息队列 Kombu 之 启动过程 0x00 摘要 本系列我们介绍消息队列 Kombu.Kombu 的定位是一个兼容 AMQP 协议的消息队列抽象.通过本文,大家可以了解 Kombu 是 ...

  5. Yii2.0源码阅读-一次请求的完整过程

    Yii2.0框架源码阅读,从请求发起,到结束的运行步骤 其实最初阅读是从yii\web\UrlManager这个类开始看起,不断的寻找这个类中方法的调用者,最终回到了yii\web\Applicati ...

  6. 源码阅读之mongoengine(0)

    最近工作上用到了mongodb,之前只是草草了解了一下.对于NoSQL的了解也不是太多.所以想趁机多学习一下. 工作的项目直接用了pymongo来操作直接操作mongodb.对于用惯了Djongo O ...

  7. Spark源码分析(一)-Standalone启动过程

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/3858065.html 为了更深入的了解spark,现开始对spark源码进行分析,本系列文章以spark ...

  8. 曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充

    文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...

  9. flume【源码分析】分析Flume的启动过程

    h2 { color: #fff; background-color: #7CCD7C; padding: 3px; margin: 10px 0px } h3 { color: #fff; back ...

随机推荐

  1. 本地eyoucms搬家

    1.后台数据备份 2.删除install 里面的install.lock 3.清理缓存文件 data - runtime-删除所有文件: 4.项目中的文件全部压缩 即打包完毕:最后再把打包的文件放置到 ...

  2. Vue-Cli 指南

    构建项目: vue create 文件夹名称 运行项目:(README文件查询) npm run serve

  3. javascript实现blob加密视频源地址

    一.HTML代码: <video id="my-video" class="video-js" playsinline controls preload= ...

  4. 基于 ECharts 封装甘特图并实现自动滚屏

    项目中需要用到甘特图组件,之前的图表一直基于 EChart 开发,但 EChart 本身没有甘特图组件,需要自行封装 经过一番鏖战,终于完成了... 我在工程中参考 v-chart 封装了一套图表组件 ...

  5. 在知识爆炸的年代如何学习,避免成为PPT架构师

    计算机的发展大体遵循摩尔定律,IT要学的东西越来越多,感觉无从下手 然后发现许多人,专门喜欢说这些名词概念装高大上,脱离一线开发,技术跟风盲目崇拜新的骚东西,比如docker,k8s,微服务,open ...

  6. shell之命令代换,将当前路径存放在变量中,然后使用变量

    重要的 命令代换`` 反引号 shell先执行该命令,然后将命令的结果存放在 变量中 例如 var=`pwd` echo $var 也可以用其$()替换 var=$(date) echo $var 删 ...

  7. iview admin动态路由实现

    参考 https://blog.csdn.net/weixin_41538490/article/details/93749942

  8. leetcode4 Median of Two Sorted Arrays学习记录

    学习了扁扁熊的题解:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/4-xun-zhao-liang-ge- ...

  9. yandexbot ip列表整理做俄罗斯市场的站长可以关注一下

    这段时间ytkah在负责一个客户的网站,主要做俄罗斯市场,当然是要研究Yandex了,首先是要知道yandexbot的ip有哪些,本文通过分析这个站从2018.12.02到2019.05.21这段时间 ...

  10. Python实战之ATM+购物车

    ATM + 购物车 需求分析 ''' - 额度 15000或自定义 - 实现购物商城,买东西加入 购物车,调用信用卡接口结账 - 可以提现,手续费5% - 支持多账户登录 - 支持账户间转账 - 记录 ...