@autowired注解原理_springBoot自动配置原理源码剖析,非常值得学习

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

d41236d0-cf78-490a-ae26-765da6b96e67

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,工程可以继承它。

87b572d9ef33475bb0da977dce076831

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

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

也就是说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 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. try {
  8. this.postProcessBeanFactory(beanFactory);
  9. this.invokeBeanFactoryPostProcessors(beanFactory);
  10. this.registerBeanPostProcessors(beanFactory);
  11. this.initMessageSource();
  12. this.initApplicationEventMulticaster();
  13. this.onRefresh();
  14. this.registerListeners();
  15. this.finishBeanFactoryInitialization(beanFactory);
  16. this.finishRefresh();
  17. } catch (BeansException var9) {
  18. if (this.logger.isWarnEnabled()) {
  19. this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
  20. }
  21. this.destroyBeans();
  22. this.cancelRefresh(var9);
  23. throw var9;
  24. } finally {
  25. this.resetCommonCaches();
  26. }
  27. }
  28. }

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实现了;

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

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

  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-INFspring.factories,找出其中key为
  15. // org.springframework.boot.autoconfigure.EnableAutoConfiguration
  16. // 的属性定义的工厂类名称。
  17. // 虽然参数有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的
  18. // 实现 getCandidateConfigurations()中,这两个参数并未使用
  19. List configurations = getCandidateConfigurations(annotationMetadata,
  20. attributes);
  21. // 去重
  22. configurations = removeDuplicates(configurations);
  23. // 排序 : 先按字典序,再按order属性,再考虑注解 @AutoConfigureBefore @AutoConfigureAfter
  24. configurations = sort(configurations, autoConfigurationMetadata);
  25. // 应用 exclusion 属性
  26. Set 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 getCandidateConfigurations(AnnotationMetadata metadata,
  54. AnnotationAttributes attributes) {
  55. List 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 filter(List 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 result = new ArrayList(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(result);
  116. }
  117. /**
  118. * 使用内部工具 SpringFactoriesLoader,查找classpath上所有jar包中的
  119. * META-INFspring.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 getAutoConfigurationImportFilters() {
  128. return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
  129. this.beanClassLoader);
  130. }
  1. protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
  2. List 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 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> loadSpringFactories(@Nullable ClassLoader classLoader) {
  2. MultiValueMap result = (MultiValueMap)cache.get(classLoader);
  3. if (result != null) {
  4. return result;
  5. } else {
  6. try {
  7. Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
  8. LinkedMultiValueMap result = new LinkedMultiValueMap();
  9. while(urls.hasMoreElements()) {
  10. URL url = (URL)urls.nextElement();
  11. UrlResource resource = new UrlResource(url);
  12. Properties properties = PropertiesLoaderUtils.loadProperties(resource);
  13. Iterator var6 = properties.entrySet().iterator();
  14. while(var6.hasNext()) {
  15. Entry, ?> entry = (Entry)var6.next();
  16. List factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));
  17. result.addAll((String)entry.getKey(), factoryClassNames);
  18. }
  19. }
  20. cache.put(classLoader, result);
  21. return result;
  22. } catch (IOException var9) {
  23. throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);
  24. }
  25. }
  26. }

而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容器中;整个自动配置结束;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值