logo头像

From zero to HERO

Spring Boot 2 实战:@SpringBootApplication注解浅析

1. 前言  

Spring Boot 都会有一个名为 xxApplication 的启动类,里面有一个标准的 java 应用的入口 main 方法,用于启动 Spring Boot 应用项目。@SpringBootApplication 是Spring Boot的核心注解,作用在启动类上,在通常情况下Spring Boot在启动时会自动扫描 @SpringBootApplication 所在类的同级包及下级包里的所有 Bean 。为什么一个小小的注解就能发挥这么大的作用?今天我们来一探究竟。

2. @SpringBootApplication

我们就从@SpringBootApplication 注解源码开始一步步揭开谜底。看看这个注解都干了什么。

2.1 @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 {};
    }

注解@SpringBootApplication 是个复合注解,集成了@ComponentScan, @EnableAutoConfiguration, @SpringBootConfiguration 三个注解。

2.2 @ComponentScan 注解

Spring里诸如@Service,@Repository,@Component,@Controller等用来向Spring IoC 容器注入bean。@ComponentScan注解就是用来自动扫描被这些注解标识的类,使得这些类被发现并最终注入Spring IoC容器。你也可以通过设置@ComponentScan中的basePackagesincludeFiltersexcludeFilters属性来动态确定自动扫描包范围和过滤规则。默认情况下:它扫描所有类型,并且扫描范围是@ComponentScan注解所在配置类包及子包的类。

2.3 @EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

这也是个复合注解,该注解可以帮助 Spring Boot 应用将所有符合条件的 @Configuration 配置都加载到当前 Spring Boot 创建并使用的 IoC 容器中。该注解的的核心要属于 @Import(AutoConfigurationImportSelector.class)AutoConfigurationImportSelector 是自动配置选择器。其中注解@Import的作用是给容器中导入一个组件。

public class AutoConfigurationImportSelector
        implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
        BeanFactoryAware, EnvironmentAware, Ordered {

    private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

    private static final String[] NO_IMPORTS = {};

    private static final Log logger = LogFactory
            .getLog(AutoConfigurationImportSelector.class);

    private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";

    private ConfigurableListableBeanFactory beanFactory;
    // 环境
    private Environment environment;
    // 类加载
    private ClassLoader beanClassLoader;
    // 资源加载
    private ResourceLoader resourceLoader;

    //----省略方法--------
}

该类实现了类加载器,资源加载器,BeanFactoryAwareEnvironmentAware,借助 SpringFactoriesLoader 工具类通过类似java SPI查找配置类的功能,实现了从 classpath 中搜寻所有 META-INF/spring.factories 配置文件,并将其中 org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的配置项通过反射实例化为标注了 @Configuration 的配置类,然后汇总加载到Spring IoC 容器。工作流程图为(来源于网络):

2.4 @SpringBootConfiguration 注解

   @Target(ElementType.TYPE)
   @Retention(RetentionPolicy.RUNTIME)
   @Documented
   @Configuration
   public @interface SpringBootConfiguration {
   }

@SpringBootConfiguration继承自@Configuration,二者功能也一致,标注当前类是配置类,并会将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到Spring IoC容器中,并且实例名就是方法名。 特别的是该注解标识这是一个 Spring Boot 项目。

3. 总结

我们简单总结一下Spring Boot的启动步骤。Spring Boot应用启动main方法后执行了一系列事件逻辑(加载环境等等)有兴趣可以去看源码,然后

  1. @SpringBootApplication起作用
  2. @SpringBootConfiguration注入配置
  3. 然后触发了@EnableAutoConfiguration 的作用:
    • 首先@AutoConfigurationPackage这个组合注解。加载AutoConfigurationPackages.Registrar类,Registrar类导入到容器中,而Registrar类作用是扫描主配置类同级目录以及子包,并将相应的组件导入到Spring Boot创建管理的容器中。
    • 然后将AutoConfigurationImportSelector导入到Spring IoC容器中,AutoConfigurationImportSelector作用是通过selectImports方法实现将配置类信息交给SpringFactoriesLoader进行一系列的容器创建过程,具体实现可查看上面的源码。
  4. @ComponentScan 扫描Spring Boot启动类同级以及子包扫描其中的Bean并注入Spring IoC容器。

评论系统未开启,无法评论!