编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

springBoot自动配置原理源码剖析,非常值得学习

wxchong 2024-08-16 06:10:24 开源技术 23 ℃ 0 评论

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。


Spring Boot特点

1. 创建独立的Spring应用程序

2. 嵌入的Tomcat,无需部署WAR文件

3. 简化Maven配置

4. 自动配置Spring

5. 提供生产就绪型功能,如指标,健康检查和外部配置

6. 绝对没有代码生成和对XML没有要求配置

安装Spring Boot

从最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用。简便起见,该框架也提供了命令行界面,它可以用来运行和测试Boot应用。框架的发布版本,包括集成的CLI(命令行界面),可以在Spring仓库中手动下载和安装。一种更为简便的方式是使用Groovy环境管理器(Groovy enVironment Manager,GVM),它会处理Boot版本的安装和管理。Boot及其CLI可以通过GVM的命令行gvm install springboot进行安装。在OS X上安装Boot可以使用Homebrew包管理器。为了完成安装,首先要使用brew tap pivotal/tap切换到Pivotal仓库中,然后执行brew install springboot命令。

要进行打包和分发的工程会依赖于像 Maven或 Gradle这样的构建系统。为了简化依赖图,Boot的功能是模块化的,通过导入Boot所谓的“starter”模块,可以将许多的依赖添加到工程之中。为了更容易地管理依赖版本和使用默认配置,框架提供了一个parent POM,工程可以继承它。

SpringBoot 知识点汇总

SpringBoot 自动配置的原理?

? 首先自动配置是配置spring-boot-autoconfigure-2.0.4.RELEASE.jar包下MATA-INF下的spring.properties 文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration所对应自动配置类。

其次springBoot启动类中的@springBootApplication隐含的引入了EnableAutoConfigurationImportSelector;

  1. // 注解链
  2. @SpringBootApplication
  3. => @EnableAutoConfiguration
  4. => @Import(EnableAutoConfigurationImportSelector.class)

在SpringApplication的run方法中,会调context = createApplicationContext();在实例化这个ConfigurableApplicationContext时,不管是AnnotationConfigEmbeddedWebApplicationContext或AnnotationConfigApplicationContext时(这两个类是专门处理Spring注解方式配置的容器,直接依赖于注解作为容器配置信息来源的IoC容器。 AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本,两者的用法以及对注解的处理方式几乎没有什么差别),都会实例化一个AnnotatedBeanDefinitionReader。例如AnnotationConfigEmbeddedWebApplicationContext实例化代码:

  1. public AnnotationConfigEmbeddedWebApplicationContext() {
  2. this.reader = new AnnotatedBeanDefinitionReader(this);
  3. this.scanner = new ClassPathBeanDefinitionScanner(this);
  4. }
  5. ?

? 这里将构造AnnotatedBeanDefinitionReader,在AnnotatedBeanDefinitionReader实例化过程中,会向beanFactory注册CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor、ConfigurationClassPostProcessor等:

  1. public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
  2. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  3. Assert.notNull(environment, "Environment must not be null");
  4. this.registry = registry;
  5. this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
  6. AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  7. }
  1. public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
  2. BeanDefinitionRegistry registry, Object source) {
  3. ?
  4. DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  5. if (beanFactory != null) {
  6. if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
  7. beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
  8. }
  9. if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
  10. beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
  11. }
  12. }
  13. ?
  14. Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
  15. ?
  16. if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  17. RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
  18. def.setSource(source);
  19. beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
  20. }
  21. ?
  22. if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  23. RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
  24. def.setSource(source);
  25. beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  26. }
  27. ?
  28. if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  29. RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
  30. def.setSource(source);
  31. beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
  32. }
  33. ?
  34. // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
  35. if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  36. RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
  37. def.setSource(source);
  38. beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
  39. }
  40. ?
  41. // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
  42. if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
  43. RootBeanDefinition def = new RootBeanDefinition();
  44. try {
  45. def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
  46. AnnotationConfigUtils.class.getClassLoader()));
  47. }
  48. catch (ClassNotFoundException ex) {
  49. throw new IllegalStateException(
  50. "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
  51. }
  52. def.setSource(source);
  53. beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
  54. }
  55. ?
  56. if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
  57. RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
  58. def.setSource(source);
  59. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
  60. }
  61. if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
  62. RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
  63. def.setSource(source);
  64. beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
  65. }
  66. ?
  67. return beanDefs;
  68. }

也就是说createApplicationContext()完后,beanFactory的beanDefinitionMap会有6个值。

SpringApplication的run方法中,在调用createApplicationContext();后会调用prepareContext(context, environment, listeners, applicationArguments,printedBanner):

  1. private void prepareContext(ConfigurableApplicationContext context,
  2. ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
  3. ApplicationArguments applicationArguments, Banner printedBanner) {
  4. // ….
  5. // Load the sources
  6. Set<Object> sources = getSources();
  7. Assert.notEmpty(sources, "Sources must not be empty");
  8. load(context, sources.toArray(new Object[sources.size()]));
  9. listeners.contextLoaded(context);
  10. }

getSources()返回的就是new SpringApplication(Application.class)传入的参数,即我们的主类,然后调用了load()方法,在load()中会生成BeanDefinitionLoader实例,并把主类注册到IOC容器中。

  OK,到这里即在调用我们熟悉的AbstractApplicationContext#refresh()前,beanFactory有7个定义好的beanDefinition。

  1. public void refresh() throws BeansException, IllegalStateException {
  2. Object var1 = this.startupShutdownMonitor;
  3. synchronized(this.startupShutdownMonitor) {
  4. this.prepareRefresh();
  5. ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
  6. this.prepareBeanFactory(beanFactory);
  7. ?
  8. try {
  9. this.postProcessBeanFactory(beanFactory);
  10. this.invokeBeanFactoryPostProcessors(beanFactory);
  11. this.registerBeanPostProcessors(beanFactory);
  12. this.initMessageSource();
  13. this.initApplicationEventMulticaster();
  14. this.onRefresh();
  15. this.registerListeners();
  16. this.finishBeanFactoryInitialization(beanFactory);
  17. this.finishRefresh();
  18. } catch (BeansException var9) {
  19. if (this.logger.isWarnEnabled()) {
  20. this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
  21. }
  22. ?
  23. this.destroyBeans();
  24. this.cancelRefresh(var9);
  25. throw var9;
  26. } finally {
  27. this.resetCommonCaches();
  28. }
  29. ?
  30. }
  31. }

ConfigurationClassPostProcessor是BeanFactoryPostProcessor的子类,会在Spring容器refresh时,invokeBeanFactoryPostProcessors(beanFactory)方法中调用到。ConfigurationClassPostProcessor会解析到我们的主类,把@Import中的类拿出来,调用它的selectImports()方法。

ConfigurationClassPostProcessor 中ConfigurationClassParser分析配置类时,如果发现注@Import(ImportSelector)的情况,就会创建一个相应的ImportSelector对象, 并调用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata), 这里 EnableAutoConfigurationImportSelector的导入@Import(EnableAutoConfigurationImportSelector.class) 就属于这种情况,所以ConfigurationClassParser会实例化一个 EnableAutoConfigurationImportSelector 并调用它的 selectImports() 方法。

  1. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  2. int registryId = System.identityHashCode(registry);
  3. if (this.registriesPostProcessed.contains(registryId)) {
  4. throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
  5. } else if (this.factoriesPostProcessed.contains(registryId)) {
  6. throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
  7. } else {
  8. this.registriesPostProcessed.add(registryId);
  9. this.processConfigBeanDefinitions(registry);
  10. }
  11. } //BeanFactoryPostProcessor接口唯一的方法,被ConfigurationClassPostProcessor实现了;
  12. ?

//该方法中对配置类中的@import中的类进行解析

  1. public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
  2. List<BeanDefinitionHolder> configCandidates = new ArrayList();
  3. String[] candidateNames = registry.getBeanDefinitionNames();
  4. String[] var4 = candidateNames;
  5. int var5 = candidateNames.length;
  6. ?
  7. for(int var6 = 0; var6 < var5; ++var6) {
  8. String beanName = var4[var6];
  9. BeanDefinition beanDef = registry.getBeanDefinition(beanName);
  10. if (!ConfigurationClassUtils.isFullConfigurationClass(beanDef) && !ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
  11. if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
  12. configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
  13. }
  14. } else if (this.logger.isDebugEnabled()) {
  15. this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
  16. }
  17. }
  18. ?
  19. if (!configCandidates.isEmpty()) {
  20. configCandidates.sort((bd1, bd2) -> {
  21. int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
  22. int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
  23. return Integer.compare(i1, i2);
  24. });
  25. SingletonBeanRegistry sbr = null;
  26. if (registry instanceof SingletonBeanRegistry) {
  27. sbr = (SingletonBeanRegistry)registry;
  28. if (!this.localBeanNameGeneratorSet) {
  29. BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");
  30. if (generator != null) {
  31. this.componentScanBeanNameGenerator = generator;
  32. this.importBeanNameGenerator = generator;
  33. }
  34. }
  35. }
  36. ?
  37. if (this.environment == null) {
  38. this.environment = new StandardEnvironment();
  39. }
  40. ?
  41. ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
  42. Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
  43. HashSet alreadyParsed = new HashSet(configCandidates.size());
  44. ?
  45. do {
  46. parser.parse(candidates);
  47. parser.validate();
  48. Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
  49. configClasses.removeAll(alreadyParsed);
  50. if (this.reader == null) {
  51. this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
  52. }
  53. ?
  54. this.reader.loadBeanDefinitions(configClasses);
  55. alreadyParsed.addAll(configClasses);
  56. candidates.clear();
  57. if (registry.getBeanDefinitionCount() > candidateNames.length) {
  58. String[] newCandidateNames = registry.getBeanDefinitionNames();
  59. Set<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
  60. Set<String> alreadyParsedClasses = new HashSet();
  61. Iterator var12 = alreadyParsed.iterator();
  62. ?
  63. while(var12.hasNext()) {
  64. ConfigurationClass configurationClass = (ConfigurationClass)var12.next();
  65. alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
  66. }
  67. ?
  68. String[] var23 = newCandidateNames;
  69. int var24 = newCandidateNames.length;
  70. ?
  71. for(int var14 = 0; var14 < var24; ++var14) {
  72. String candidateName = var23[var14];
  73. if (!oldCandidateNames.contains(candidateName)) {
  74. BeanDefinition bd = registry.getBeanDefinition(candidateName);
  75. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {
  76. candidates.add(new BeanDefinitionHolder(bd, candidateName));
  77. }
  78. }
  79. }
  80. ?
  81. candidateNames = newCandidateNames;
  82. }
  83. } while(!candidates.isEmpty());
  84. ?
  85. if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
  86. sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
  87. }
  88. ?
  89. if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
  90. ((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();
  91. }
  92. ?
  93. }
  94. }
  1. public void parse(Set<BeanDefinitionHolder> configCandidates) {
  2. this.deferredImportSelectors = new LinkedList();
  3. Iterator var2 = configCandidates.iterator();
  4. ?
  5. while(var2.hasNext()) {
  6. BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
  7. BeanDefinition bd = holder.getBeanDefinition();
  8. ?
  9. try {
  10. if (bd instanceof AnnotatedBeanDefinition) {
  11. this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
  12. } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
  13. this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
  14. } else {
  15. this.parse(bd.getBeanClassName(), holder.getBeanName());
  16. }
  17. } catch (BeanDefinitionStoreException var6) {
  18. throw var6;
  19. } catch (Throwable var7) {
  20. throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
  21. }
  22. }
  23. ?
  24. this.processDeferredImportSelectors();
  25. }
  1. private void processDeferredImportSelectors() {
  2. List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
  3. this.deferredImportSelectors = null;
  4. if (deferredImports != null) {
  5. deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
  6. Map<Object, ConfigurationClassParser.DeferredImportSelectorGrouping> groupings = new LinkedHashMap();
  7. Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap();
  8. Iterator var4 = deferredImports.iterator();
  9. ?
  10. while(var4.hasNext()) {
  11. ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var4.next();
  12. Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
  13. ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)groupings.computeIfAbsent(group != null ? group : deferredImport, (key) -> {
  14. return new ConfigurationClassParser.DeferredImportSelectorGrouping(this.createGroup(group));
  15. });
  16. grouping.add(deferredImport);
  17. configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass());
  18. }
  19. ?
  20. var4 = groupings.values().iterator();
  21. ?
  22. while(var4.hasNext()) {
  23. ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)var4.next();
  24. grouping.getImports().forEach((entry) -> {
  25. ConfigurationClass configurationClass = (ConfigurationClass)configurationClasses.get(entry.getMetadata());
  26. ?
  27. try {
  28. this.processImports(configurationClass, this.asSourceClass(configurationClass), this.asSourceClasses(entry.getImportClassName()), false); //调用processImports方法
  29. } catch (BeanDefinitionStoreException var5) {
  30. throw var5;
  31. } catch (Throwable var6) {
  32. throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", var6);
  33. }
  34. });
  35. }
  36. ?
  37. }
  38. }
  1. private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, boolean checkForCircularImports) {
  2. if (!importCandidates.isEmpty()) {
  3. if (checkForCircularImports && this.isChainedImportOnStack(configClass)) {
  4. this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack));
  5. } else {
  6. this.importStack.push(configClass);
  7. ?
  8. try {
  9. Iterator var5 = importCandidates.iterator();
  10. ?
  11. while(true) {
  12. while(true) {
  13. while(var5.hasNext()) {
  14. ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var5.next();
  15. Class candidateClass;
  16. if (candidate.isAssignable(ImportSelector.class)) {
  17. candidateClass = candidate.loadClass();
  18. ImportSelector selector = (ImportSelector)BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
  19. ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);
  20. if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
  21. this.deferredImportSelectors.add(new ConfigurationClassParser.DeferredImportSelectorHolder(configClass, (DeferredImportSelector)selector));
  22. } else {
  23. String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); //执行@import类的selectImports方法;
  24. Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames);
  25. this.processImports(configClass, currentSourceClass, importSourceClasses, false);
  26. }
  27. } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
  28. candidateClass = candidate.loadClass();
  29. ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
  30. ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
  31. configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
  32. } else {
  33. this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
  34. this.processConfigurationClass(candidate.asConfigClass(configClass));
  35. }
  36. }
  37. ?
  38. return;
  39. }
  40. }
  41. } catch (BeanDefinitionStoreException var15) {
  42. throw var15;
  43. } catch (Throwable var16) {
  44. throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var16);
  45. } finally {
  46. this.importStack.pop();
  47. }
  48. }
  49. }
  50. }

?

  1. // selectImports 的具体执行逻辑 注释参考https://blog.csdn.net/andy_zhang2007/article/details/78580980
  2. @Override
  3. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  4. if (!isEnabled(annotationMetadata)) {
  5. return NO_IMPORTS;
  6. }
  7. try {
  8. // 从配置文件中加载 AutoConfigurationMetadata
  9. AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
  10. .loadMetadata(this.beanClassLoader);
  11. AnnotationAttributes attributes = getAttributes(annotationMetadata);
  12. // 获取所有候选配置类EnableAutoConfiguration
  13. // 使用了内部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的
  14. // META-INF\spring.factories,找出其中key为
  15. // org.springframework.boot.autoconfigure.EnableAutoConfiguration
  16. // 的属性定义的工厂类名称。
  17. // 虽然参数有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的
  18. // 实现 getCandidateConfigurations()中,这两个参数并未使用
  19. List<String> configurations = getCandidateConfigurations(annotationMetadata,
  20. attributes);
  21. // 去重
  22. configurations = removeDuplicates(configurations);
  23. // 排序 : 先按字典序,再按order属性,再考虑注解 @AutoConfigureBefore @AutoConfigureAfter
  24. configurations = sort(configurations, autoConfigurationMetadata);
  25. // 应用 exclusion 属性
  26. Set<String> exclusions = getExclusions(annotationMetadata, attributes);
  27. checkExcludedClasses(configurations, exclusions);
  28. configurations.removeAll(exclusions);
  29. // 应用过滤器AutoConfigurationImportFilter,
  30. // 对于 spring boot autoconfigure,定义了一个需要被应用的过滤器 :
  31. // org.springframework.boot.autoconfigure.condition.OnClassCondition,
  32. // 此过滤器检查候选配置类上的注解@ConditionalOnClass,如果要求的类在classpath
  33. // 中不存在,则这个候选配置类会被排除掉
  34. configurations = filter(configurations, autoConfigurationMetadata);
  35. // 现在已经找到所有需要被应用的候选配置类
  36. // 广播事件 AutoConfigurationImportEvent
  37. fireAutoConfigurationImportEvents(configurations, exclusions);
  38. return configurations.toArray(new String[configurations.size()]);
  39. }
  40. catch (IOException ex) {
  41. throw new IllegalStateException(ex);
  42. }
  43. }
  44. /**
  45. * Return the auto-configuration class names that should be considered. By default
  46. * this method will load candidates using SpringFactoriesLoader with
  47. * getSpringFactoriesLoaderFactoryClass().
  48. * @param metadata the source metadata
  49. * @param attributes the getAttributes(AnnotationMetadata) annotation
  50. * attributes
  51. * @return a list of candidate configurations
  52. */
  53. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
  54. AnnotationAttributes attributes) {
  55. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
  56. getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
  57. Assert.notEmpty(configurations,
  58. "No auto configuration classes found in META-INF/spring.factories. If you "
  59. + "are using a custom packaging, make sure that file is correct.");
  60. return configurations;
  61. }

  62. /**
  63. * Return the class used by SpringFactoriesLoader to load configuration
  64. * candidates.
  65. * @return the factory class
  66. */
  67. protected Class<?> getSpringFactoriesLoaderFactoryClass() {
  68. return EnableAutoConfiguration.class;
  69. }
  70. /**
  71. * 根据autoConfigurationMetadata信息对候选配置类configurations进行过滤
  72. **/
  73. private List<String> filter(List<String> configurations,
  74. AutoConfigurationMetadata autoConfigurationMetadata) {
  75. long startTime = System.nanoTime();
  76. String[] candidates = configurations.toArray(new String[configurations.size()]);
  77. // 记录候选配置类是否需要被排除,skip为true表示需要被排除,全部初始化为false,不需要被排除
  78. boolean[] skip = new boolean[candidates.length];
  79. // 记录候选配置类中是否有任何一个候选配置类被忽略,初始化为false
  80. boolean skipped = false;
  81. // 获取AutoConfigurationImportFilter并逐个应用过滤
  82. for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
  83. // 对过滤器注入其需要Aware的信息
  84. invokeAwareMethods(filter);
  85. // 使用此过滤器检查候选配置类跟autoConfigurationMetadata的匹配情况
  86. boolean[] match = filter.match(candidates, autoConfigurationMetadata);
  87. for (int i = 0; i < match.length; i++) {
  88. if (!match[i]) {
  89. // 如果有某个候选配置类不符合当前过滤器,将其标记为需要被排除,
  90. // 并且将 skipped设置为true,表示发现了某个候选配置类需要被排除
  91. skip[i] = true;
  92. skipped = true;
  93. }
  94. }
  95. }
  96. if (!skipped) {
  97. // 如果所有的候选配置类都不需要被排除,则直接返回外部参数提供的候选配置类集合
  98. return configurations;
  99. }
  100. // 逻辑走到这里因为skipped为true,表明上面的的过滤器应用逻辑中发现了某些候选配置类
  101. // 需要被排除,这里排除那些需要被排除的候选配置类,将那些不需要被排除的候选配置类组成
  102. // 一个新的集合返回给调用者
  103. List<String> result = new ArrayList<String>(candidates.length);
  104. for (int i = 0; i < candidates.length; i++) {
  105. if (!skip[i]) {
  106. result.add(candidates[i]);
  107. }
  108. }
  109. if (logger.isTraceEnabled()) {
  110. int numberFiltered = configurations.size() - result.size();
  111. logger.trace("Filtered " + numberFiltered + " auto configuration class in "
  112. + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
  113. + " ms");
  114. }
  115. return new ArrayList<String>(result);
  116. }
  117. /**
  118. * 使用内部工具 SpringFactoriesLoader,查找classpath上所有jar包中的
  119. * META-INF\spring.factories,找出其中key为
  120. * org.springframework.boot.autoconfigure.AutoConfigurationImportFilter
  121. * 的属性定义的过滤器类并实例化。
  122. * AutoConfigurationImportFilter过滤器可以被注册到 spring.factories用于对自动配置类
  123. * 做一些限制,在这些自动配置类的字节码被读取之前做快速排除处理。
  124. * spring boot autoconfigure 缺省注册了一个 AutoConfigurationImportFilter :
  125. * org.springframework.boot.autoconfigure.condition.OnClassCondition
  126. **/
  127. protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
  128. return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
  129. this.beanClassLoader);
  130. }
  1. protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  2. List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
  3. Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
  4. return configurations;
  5. }
  1. public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
  2. String factoryClassName = factoryClass.getName();
  3. return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
  4. }
  1. private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
  2. MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
  3. if (result != null) {
  4. return result;
  5. } else {
  6. try {
  7. Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
  8. LinkedMultiValueMap result = new LinkedMultiValueMap();
  9. ?
  10. while(urls.hasMoreElements()) {
  11. URL url = (URL)urls.nextElement();
  12. UrlResource resource = new UrlResource(url);
  13. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  14. Iterator var6 = properties.entrySet().iterator();
  15. ?
  16. while(var6.hasNext()) {
  17. Entry<?, ?> entry = (Entry)var6.next();
  18. List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
  19. result.addAll((String)entry.getKey(), factoryClassNames);
  20. }
  21. }
  22. ?
  23. cache.put(classLoader, result);
  24. return result;
  25. } catch (IOException var9) {
  26. throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
  27. }
  28. }
  29. }

而loadSpringFactories会扫描所有jar包下的 META‐INF/spring.factories文件,并封装成properties属性对象;并以key-value的形式存放在MultiValueMap对象中,List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置时,只需要获取key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的list保存的value,然后返回到processImports方法中,最终注册到IOC容器中;整个自动配置结束;

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表