我们都直到 Spring Boot 通过一些注解就可以完成一些功能的配置,如:只需要简单的在 application.yml 中配置一些 Redis 的相关参数就可以使用 redis 了,这些是如何做到的呢?

@SpringBootApplication

我们先看 @SpringBootApplication 注解里有什么?

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @SpringBootConfiguration
  6. @EnableAutoConfiguration // 开启自动配置
  7. @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
  8. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  9. public @interface SpringBootApplication {
  10. // ...
  11. }

我们看到了一个 @EnableAutoConfiguration 这个注解,从名字就可以看出,这个是允许自动配置的意思,我们继续看这个注解又干了什么事?

@EnableAutoConfiguration

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. @AutoConfigurationPackage
  6. @Import(AutoConfigurationImportSelector.class) // 利用 @Import 导入 AutoConfigurationImportSelector.class
  7. public @interface EnableAutoConfiguration {
  8. // ...
  9. }

这个包上有一个注解 @Import(AutoConfigurationImportSelector.class),我们都知道 @Import 是导入一个类到 Spring 容器中,这里我们可以看到,SpringBoot 把 AutoConfigurationImportSelector.class 类加载到了容器里,那这个类有什么特殊的地方呢?

AutoConfigurationImportSelector.class

我们看一下 AutoConfigurationImportSelector 这个类的定义

  1. public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
  2. ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
  3. // ...
  4. }

AutoConfigurationImportSelector 实现了 DeferredImportSelector 接口,而 DeferredImportSelector 接口又继承了 ImportSelector 接口,接下来我们看一下 ImportSelector 接口主要是做什么的

ImportSelector 接口

ImportSelector 接口只有一个方法 selectImports

  1. public interface ImportSelector {
  2. /**
  3. * Select and return the names of which class(es) should be imported based on
  4. * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
  5. */
  6. String[] selectImports(AnnotationMetadata importingClassMetadata);
  7. }

通过注释我们可以知道,这个类主要就是返回一个 String 数组,数组里是需要加入到 Spring 容器的全类名,也就是说,我们只要在数据中添加 com.example.Xxx 类,Spring 就会将这个 com.example.Xxx 类加入到 Spring 容器中,那么 SpringBoot 会返回什么样的类出来呢?

我们看下 AutoConfigurationImportSelector 是如何实现这个接口方法的

  1. @Override
  2. public String[] selectImports(AnnotationMetadata annotationMetadata) {
  3. if (!isEnabled(annotationMetadata)) {
  4. return NO_IMPORTS;
  5. }
  6. AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
  7. return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
  8. }

我们继续跟 getAutoConfigurationEntry 方法,会发现 Spring 会读取 META-INF\spring.factories 里的所有类,将其转换为 String 数组返回给 Spring 容器

spring.factories 文件

  1. # Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
  4. org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
  5. # Application Listeners
  6. org.springframework.context.ApplicationListener=\
  7. org.springframework.boot.autoconfigure.BackgroundPreinitializer
  8. # Auto Configuration Import Listeners
  9. org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
  10. org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
  11. # Auto Configuration Import Filters
  12. org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
  13. org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
  14. org.springframework.boot.autoconfigure.condition.OnClassCondition,\
  15. org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
  16. # Auto Configure
  17. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  18. org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
  19. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  20. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  21. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  22. org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\