Spring Boot 探索之旅(三)——Boot项目启动运行原理

╰半橙微兮° 2022-05-10 03:44 286阅读 0赞

一、boot项目核心注解@SpringBootApplication

首先进入SpringBootApplication源码分析

  1. @Target(ElementType.TYPE)//注解生效地点:类
  2. @Retention(RetentionPolicy.RUNTIME)//注解生效时间:运行期
  3. @Documented//生成文档
  4. @Inherited//该注解可以被继承
  5. @SpringBootConfiguration//表明自身是一个配置类
  6. @EnableAutoConfiguration//开启自动配置(核心关键)
  7. @ComponentScan(excludeFilters = {
  8. @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  9. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })//默认扫描该类同包及其子包所有类的所有注解
  10. public @interface SpringBootApplication {
  11. /**
  12. * 按类排除
  13. */
  14. @AliasFor(annotation = EnableAutoConfiguration.class)
  15. Class<?>[] exclude() default {};
  16. /**
  17. * 按类名排除
  18. */
  19. @AliasFor(annotation = EnableAutoConfiguration.class)
  20. String[] excludeName() default {};
  21. /**
  22. * 扫描具有componenScan注解的类名
  23. */
  24. @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
  25. String[] scanBasePackages() default {};
  26. /**
  27. * 扫描具有componenScan注解的类
  28. */
  29. @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
  30. Class<?>[] scanBasePackageClasses() default {};
  31. }

再进入EnableAutoConfiguration源码分析

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class)//导入配置选择器
  7. public @interface EnableAutoConfiguration {
  8. String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
  9. /**
  10. * 按类解除自动配置
  11. */
  12. Class<?>[] exclude() default {};
  13. /**
  14. *按类名解除自动配置
  15. */
  16. String[] excludeName() default {};
  17. }

对导入的AutoConfigurationImportSelector分析

  1. public class AutoConfigurationImportSelector
  2. implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
  3. BeanFactoryAware, EnvironmentAware, Ordered {
  4. private static final String[] NO_IMPORTS = {};
  5. private static final Log logger = LogFactory
  6. .getLog(AutoConfigurationImportSelector.class);
  7. private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
  8. private ConfigurableListableBeanFactory beanFactory;
  9. private Environment environment;
  10. private ClassLoader beanClassLoader;
  11. private ResourceLoader resourceLoader;
  12. @Override
  13. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  14. //如果开关关闭,则不做任何自动配置
  15. if (!isEnabled(annotationMetadata)) {
  16. return NO_IMPORTS;
  17. }
  18. //通过类加载器获取默认配置数据
  19. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  20. .loadMetadata(this.beanClassLoader);
  21. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  22. List<String> configurations = getCandidateConfigurations(annotationMetadata,
  23. attributes);
  24. configurations = removeDuplicates(configurations);
  25. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  26. //排除解除自动配置的类
  27. checkExcludedClasses(configurations, exclusions);
  28. configurations.removeAll(exclusions);
  29. configurations = filter(configurations, autoConfigurationMetadata);
  30. fireAutoConfigurationImportEvents(configurations, exclusions);
  31. return StringUtils.toStringArray(configurations);
  32. }
  33. @Override
  34. public Class<? extends Group> getImportGroup() {
  35. return AutoConfigurationGroup.class;
  36. }
  37. protected boolean isEnabled(AnnotationMetadata metadata) {
  38. if (getClass() == AutoConfigurationImportSelector.class) {
  39. return getEnvironment().getProperty(
  40. EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class,
  41. true);
  42. }
  43. return true;
  44. }
  45. /**
  46. * Return the appropriate {@link AnnotationAttributes} from the
  47. * {@link AnnotationMetadata}. By default this method will return attributes for
  48. * {@link #getAnnotationClass()}.
  49. * @param metadata the annotation metadata
  50. * @return annotation attributes
  51. */
  52. protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
  53. String name = getAnnotationClass().getName();
  54. AnnotationAttributes attributes = AnnotationAttributes
  55. .fromMap(metadata.getAnnotationAttributes(name, true));
  56. Assert.notNull(attributes,
  57. () -> "No auto-configuration attributes found. Is "
  58. + metadata.getClassName() + " annotated with "
  59. + ClassUtils.getShortName(name) + "?");
  60. return attributes;
  61. }
  62. /**
  63. * Return the source annotation class used by the selector.
  64. * @return the annotation class
  65. */
  66. protected Class<?> getAnnotationClass() {
  67. return EnableAutoConfiguration.class;
  68. }
  69. /**
  70. * Return the auto-configuration class names that should be considered. By default
  71. * this method will load candidates using {@link SpringFactoriesLoader} with
  72. * {@link #getSpringFactoriesLoaderFactoryClass()}.
  73. * @param metadata the source metadata
  74. * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
  75. * attributes}
  76. * @return a list of candidate configurations
  77. */
  78. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
  79. AnnotationAttributes attributes) {
  80. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
  81. getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
  82. Assert.notEmpty(configurations,
  83. "No auto configuration classes found in META-INF/spring.factories. If you "
  84. + "are using a custom packaging, make sure that file is correct.");
  85. return configurations;
  86. }
  87. 。。。。

探究AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader)

  1. final class AutoConfigurationMetadataLoader {
  2. //在autoconfiguration依赖中
  3. protected static final String PATH = "META-INF/"
  4. + "spring-autoconfigure-metadata.properties";
  5. private AutoConfigurationMetadataLoader() {
  6. }
  7. public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
  8. return loadMetadata(classLoader, PATH);
  9. }
  10. static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
  11. //加载默认配置
  12. try {
  13. Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
  14. : ClassLoader.getSystemResources(path);
  15. Properties properties = new Properties();
  16. while (urls.hasMoreElements()) {
  17. properties.putAll(PropertiesLoaderUtils
  18. .loadProperties(new UrlResource(urls.nextElement())));
  19. }
  20. return loadMetadata(properties);
  21. }
  22. catch (IOException ex) {
  23. throw new IllegalArgumentException(
  24. "Unable to load @ConditionalOnClass location [" + path + "]", ex);
  25. }
  26. }
  27. static AutoConfigurationMetadata loadMetadata(Properties properties) {
  28. return new PropertiesAutoConfigurationMetadata(properties);
  29. }
  30. /**
  31. * {@link AutoConfigurationMetadata} implementation backed by a properties file.
  32. */
  33. private static class PropertiesAutoConfigurationMetadata
  34. implements AutoConfigurationMetadata {
  35. private final Properties properties;
  36. PropertiesAutoConfigurationMetadata(Properties properties) {
  37. this.properties = properties;
  38. }
  39. @Override
  40. public boolean wasProcessed(String className) {
  41. return this.properties.containsKey(className);
  42. }
  43. @Override
  44. public Integer getInteger(String className, String key) {
  45. return getInteger(className, key, null);
  46. }
  47. @Override
  48. public Integer getInteger(String className, String key, Integer defaultValue) {
  49. String value = get(className, key);
  50. return (value != null) ? Integer.valueOf(value) : defaultValue;
  51. }
  52. @Override
  53. public Set<String> getSet(String className, String key) {
  54. return getSet(className, key, null);
  55. }
  56. @Override
  57. public Set<String> getSet(String className, String key,
  58. Set<String> defaultValue) {
  59. String value = get(className, key);
  60. return (value != null) ? StringUtils.commaDelimitedListToSet(value)
  61. : defaultValue;
  62. }
  63. @Override
  64. public String get(String className, String key) {
  65. return get(className, key, null);
  66. }
  67. @Override
  68. public String get(String className, String key, String defaultValue) {
  69. String value = this.properties.getProperty(className + "." + key);
  70. return (value != null) ? value : defaultValue;
  71. }
  72. }
  73. }

查看spring-autoconfigure-metadata.properties文件

70

二、Spring Boot核心Main方法

  1. ** 分析SpringApplication.run方法**
  2. public ConfigurableApplicationContext run(String... args) {
  3. //StopWatch检查项目启动所需时间
  4. StopWatch stopWatch = new StopWatch();
  5. stopWatch.start();
  6. //创建项目上下文对象
  7. ConfigurableApplicationContext context = null;
  8. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
  9. configureHeadlessProperty();
  10. // 从配置中获取SpringApplicationRunListener实现类并实例化,
  11. // 最终把所有这些实例包装到一个SpringApplicationRunListeners实例来使用
  12. SpringApplicationRunListeners listeners = getRunListeners(args);
  13. listeners.starting();
  14. try {
  15. ApplicationArguments applicationArguments = new DefaultApplicationArguments(
  16. args);
  17. ConfigurableEnvironment environment = prepareEnvironment(listeners,
  18. applicationArguments);
  19. configureIgnoreBeanInfo(environment);
  20. Banner printedBanner = printBanner(environment);
  21. // 这里创建应用上下文
  22. context = createApplicationContext();
  23. exceptionReporters = getSpringFactoriesInstances(
  24. SpringBootExceptionReporter.class,
  25. new Class[] { ConfigurableApplicationContext.class }, context);
  26. prepareContext(context, environment, listeners, applicationArguments,
  27. printedBanner);
  28. refreshContext(context);
  29. afterRefresh(context, applicationArguments);
  30. stopWatch.stop();
  31. if (this.logStartupInfo) {
  32. new StartupInfoLogger(this.mainApplicationClass)
  33. .logStarted(getApplicationLog(), stopWatch);
  34. }
  35. listeners.started(context);
  36. callRunners(context, applicationArguments);
  37. }
  38. catch (Throwable ex) {
  39. handleRunFailure(context, ex, exceptionReporters, listeners);
  40. throw new IllegalStateException(ex);
  41. }
  42. try {
  43. listeners.running(context);
  44. }
  45. catch (Throwable ex) {
  46. handleRunFailure(context, ex, exceptionReporters, null);
  47. throw new IllegalStateException(ex);
  48. }
  49. return context;
  50. }

发表评论

表情:
评论列表 (有 0 条评论,286人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Spring Boot 运行原理

           Spring Boot的优势在于内置大量习惯性的配置,便于与第三方集成,即“习惯优于配置”,让项目能够快速运行起来,下面我们就探究下Spring Boot自动集成

    相关 Spring Boot运行原理

    Spring Boot方式的项目开发已经逐步成为Java应用开发领域的主流框架,它不仅可以方便地创建生产级的Spring应用程序,还能轻松地通过一些注解配置与目前比较流行的微服