1 SpringBoot运作原理
上一章中我们提到主程序类的注解 @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 { @AliasFor( annotation = EnableAutoConfiguration.class ) Class<?>[] exclude() default {}; @AliasFor( annotation = EnableAutoConfiguration.class ) String[] excludeName() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "basePackages" ) String[] scanBasePackages() default {}; @AliasFor( annotation = ComponentScan.class, attribute = "basePackageClasses" ) Class<?>[] scanBasePackageClasses() default {}; }
最主要的还是三个配置 @SpringBootConfiguration、@EnableAutoConfigration、@ComponentScan 三个注解,下面我们来一一分析。
1.1 @SpringBootConfiguration
查看@SpringBootConfiguration源码,其实它也就是@Configuration注解:
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
对于 @Configuration,我们并不陌生,它就是 JavaConfig 形式的 SpringIOC 容器的配置类,也是 SpringBoot 推荐使用配置形式,所以主程序类标注了 @SpringBootConfiguration 注解,其本身也就是一个配置类。更多有关 JavaConfig 形式的配置以及有关它和 XML 形式的配置的区别与联系,请参考后续有关 Spring 注解版相关文章。
1.2 @ComponentScan
@ComponentScan 注解在 Spring 的注解中也起到到相当重要的作用,它可以自定义 Spring 扫描的包,也就是它默认会扫描标注了 @Controller、@Service、@Component 以及 @Repository 注解的类,并实例化这些组件到 SpringIOC 容器中,它有个配置属性: basePackages,也就是指定扫描的包,如果不知道,它会默认扫描配置了该注解的类的包所在的路径(包括子包)。我们看 @SpringBootConfiguration 注解的源码中有段代码:
@AliasFor( annotation = ComponentScan.class, attribute = "basePackages" ) String[] scanBasePackages() default {};
scanBasePackages 属性,指定到了 @ComponentScan 注解的 basePackages 属性,所有在 SpringBoot 中,我们同样可以通过 scanBasePackages 属性指定包扫描的路径(如部指定,会默认扫描主程序类所在的包路径以及子包下的类):
@SpringBootApplication(scanBasePackages = "com.seagetech.springbootdemo")
1.3 @EnableAutoConfigration
关于 SpringBoot 的运作原理,它的核心功能还是由 @EnableAutoConfigration 注解提供,所有把它放到最后来讲,我们来看下它的源码:
@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 {}; }
1.3.1 @AutoConfigurationPackage
这个注解的主要功能自动配置包,它会获取主程序类所在的包路径,并将包路径(包括子包)下的所有组件注册到 SpringIOC 容器中。
1.3.2 @Import({AutoConfigurationImportSelector.class})
@EnableAutoConfiguration 的关键功能也是这个 @Import 导入的配置功能,使用 SpringFactoriesLoader.loadFactoryNames 方法来扫描具有 META-INF/spring.factories 文件的jar包,我们看看在 spring-boot-autoconfigure-2.10.RELEASE.jar 包的 META-INF 下正好有个 spring.factories 文件:
打开 spring.factories 文件,找到 org.springframework.boot.autoconfigure.EnableAutoConfiguration 指定的自动配置类:
# Auto Configure org.springframework.boot.autoconfigure.Ena