我们都直到 Spring Boot 通过一些注解就可以完成一些功能的配置,如:只需要简单的在 application.yml 中配置一些 Redis 的相关参数就可以使用 redis 了,这些是如何做到的呢?
@SpringBootApplication
我们先看 @SpringBootApplication 注解里有什么?
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration // 开启自动配置@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {// ...}
我们看到了一个 @EnableAutoConfiguration 这个注解,从名字就可以看出,这个是允许自动配置的意思,我们继续看这个注解又干了什么事?
@EnableAutoConfiguration
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class) // 利用 @Import 导入 AutoConfigurationImportSelector.classpublic @interface EnableAutoConfiguration {// ...}
这个包上有一个注解 @Import(AutoConfigurationImportSelector.class),我们都知道 @Import 是导入一个类到 Spring 容器中,这里我们可以看到,SpringBoot 把 AutoConfigurationImportSelector.class 类加载到了容器里,那这个类有什么特殊的地方呢?
AutoConfigurationImportSelector.class
我们看一下 AutoConfigurationImportSelector 这个类的定义
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {// ...}
AutoConfigurationImportSelector 实现了 DeferredImportSelector 接口,而 DeferredImportSelector 接口又继承了 ImportSelector 接口,接下来我们看一下 ImportSelector 接口主要是做什么的
ImportSelector 接口
ImportSelector 接口只有一个方法 selectImports
public interface ImportSelector {/*** Select and return the names of which class(es) should be imported based on* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.*/String[] selectImports(AnnotationMetadata importingClassMetadata);}
通过注释我们可以知道,这个类主要就是返回一个 String 数组,数组里是需要加入到 Spring 容器的全类名,也就是说,我们只要在数据中添加 com.example.Xxx 类,Spring 就会将这个 com.example.Xxx 类加入到 Spring 容器中,那么 SpringBoot 会返回什么样的类出来呢?
我们看下 AutoConfigurationImportSelector 是如何实现这个接口方法的
@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
我们继续跟 getAutoConfigurationEntry 方法,会发现 Spring 会读取 META-INF\spring.factories 里的所有类,将其转换为 String 数组返回给 Spring 容器
spring.factories 文件
# Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.autoconfigure.BackgroundPreinitializer# Auto Configuration Import Listenersorg.springframework.boot.autoconfigure.AutoConfigurationImportListener=\org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener# Auto Configuration Import Filtersorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\org.springframework.boot.autoconfigure.condition.OnBeanCondition,\org.springframework.boot.autoconfigure.condition.OnClassCondition,\org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
