Spring Boot自动配置
前面提到过,Spring Boot应用的启动入口是@SpringBootApplication注解标注类中的main()方法,@SpringBootApplication能够扫描Spring组件并自动配置Spring Boot,到底是如何自动配置Spring Boot的呢?下面,查看@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 {
...
}
从上述源码可以看出,@SpringBootApplication注解是一个组合注解,包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个核心注解,关于这三个核心注解的相关说明具体如下。
1.@SpringBootConfiguration注解
@SpringBootConfiguration注解表示Spring Boot配置类。查看@SpringBootConfiguration注解源码,核心代码具体如下。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
从上述源码可以看出,@SpringBootConfiguration注解内部有一个核心注解@Configuration,该注解是Spring框架提供的,表示当前类为一个配置类(XML配置文件的注解表现形式),并可以被组件扫描器扫描。由此可见,@SpringBootConfiguration注解的作用与@Configuration注解相同,都是标识一个可以被组件扫描器扫描的配置类,只不过@SpringBootConfiguration是被Spring Boot进行了重新封装命名而已。
2.@EnableAutoConfiguration注解
@EnableAutoConfiguration注解表示开启自动配置功能,该注解是Spring Boot框架最重要的注解,也是实现自动化配置的注解。同样,查看该注解内部查看源码信息,核心代码具体如下。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage // 自动配置包
@Import({AutoConfigurationImportSelector.class}) // 自动配置类扫描导入
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
从上述源码可以看出,@EnableAutoConfiguration注解是一个组合注解,它主要包括有@AutoConfigurationPackage和@Import两个核心注解。下面,对这两个核心注解分别讲解。
(1)@AutoConfigurationPackage注解
查看@AutoConfigurationPackage注解内部源码信息,核心代码具体如下。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class}) // 导入Registrar中注册的组件
public @interface AutoConfigurationPackage {
}
从上述源码可以看出,@AutoConfigurationPackage注解的功能是由@Import注解实现的,作用是向容器导入注册的所有组件,导入的组件由Registrar决定。查看Registrar类源码信息,核心代码具体如下。
static class Registrar implements ImportBeanDefinitionRegistrar,DeterminableImports{
Registrar() { }
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry,
(new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
...
}
从上述源码可以看出,在Registrar类中有一个registerBeanDefinitions()方法,使用Debug模式启动项目,会发现上述代码中加粗部分获取的是项目主程序启动类所在的目录com.itheima。也就是说,@AutoConfigurationPackage注解的主要作用是获取项目主程序启动类所在根目录,从而指定后续组件扫描器要扫描的包位置。因此 在定义项目包结构时,要求定义的包结构非常规范,项目主程序启动类要定义在最外层的根目录位置,然后在根目录位置内部建立子包和类进行业务开发,这样才能够保证定义的类能够被组件扫描器扫描。
(2)@Import({AutoConfigurationImportSelector.class})注解
查看AutoConfigurationImportSelector类的getAutoConfigurationEntry()方法,核心代码具体如下。
protected AutoConfigurationImportSelector.AutoConfigurationEntry
getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 获取所有Spring Boot提供的后续自动配置类XxxAutoConfiguration
List<String> configurations =
this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 筛选并过滤出当前应用环境下需要的自动配置类XxxAutoConfiguration
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(
configurations, exclusions);
}
}
在上述展示的getAutoConfigurationEntry()方法,其主要作用是筛选出当前项目环境需要启动的自动配置类XxxAutoConfiguration,从而实现当前项目运行所需的自动配置环境。另外,在上述核心方法中加粗显示了2个重要的业务处理方法,具体说明如下。
● this.getCandidateConfigurations(annotationMetadata, attributes)方法:该方法的主要作用是从Spring Boot提供的自动配置依赖的META-INF/spring.factories文件中获取所有候选自动配置类XxxAutoConfiguration(2.1.3版本提供有121个自动配置类);
● this.filter(configurations, autoConfigurationMetadata)方法:该方法的作用是对所有候选的自动配置类进行筛选,根据项目pom.xml文件中加入的依赖文件筛选出最终符合当前项目运行环境对应的自动配置类(筛选完成后可能只有25个)。
为了让初学者更清楚的知道META-INF/spring.factories类路径下META-INF下的spring.factores文件中Spring Boot提供的候选自动配置类XxxAutoConfiguration有哪些,这里以chapter01项目结构为例进行展示说明,具体如图1所示。
图1 META-INF/spring.factories下Spring Boot自动配置类
同样以chapter01项目为例,在项目中加入了Web环境依赖启动器,对应的WebMvcAutoConfiguration自动配置类就会生效,打开该自动配置类会发现,在该配置类中通过全注解配置类的方式对Spring MVC运行所需环境进行了默认配置,包括默认前缀、默认后缀、视图解析器、MVC校验器等。而这些自动配置类的本质是传统Spring MVC框架中对应的XML配置文件,只不过在Spring Boot中以自动配置类的形式进行了预先配置。因此,在Spring Boot项目中加入相关依赖启动器后,基本上不需要任何配置就可以运行程序,当然,我们也可以对这些自动配置类中默认的配置进行更改。
3.@ComponentScan注解
@ComponentScan注解是一个组件包扫描器,其主要作用是扫描指定包及其子包下所有注解类文件作为Spring容器的组件使用。
@ComponentScan注解具体扫描的包的根路径由Spring Boot项目主程序启动类所在包位置决定,在扫描过程中由前面介绍的@AutoConfigurationPackage注解进行解析,从而得到Spring Boot项目主程序启动类所在包的具体位置。