程序员社区

@SpringBootApplication注解分析


源码分析,基于 Spring Boot 1.5.10 版本

        通过前面内容【Spring Boot 工程创建】介绍,我们了解到 Spring Boot 项目需要在一个类上添加 @SpringBootApplication注解,然后执行该类下的 main() 方法,即可启动容器。接下来就从 @SpringBootApplication 注解来分析一下它的具体执行流程。

/** * @SpringBootApplication 来标注一个主程序类,说明这是一个Spring Boot应用 */
@SpringBootApplication
public class BootApplication {
   

    public static void main(String[] args) {
   
        // Spring应用启动起来 
        SpringApplication.run(BootApplication.class,args);
    }
}

@SpringBootApplication注解分析

        该注解是一个组合注解。它主要由@SpringBootConfiguration@EnableAutoConfiguration这两个注解组成。

        @SpringBootApplication 标注在某个类上,说明这个类是 Spring Boot 的主配置类,Spring Boot 就会运行这个类的 main 方法来启动 Spring Boot 应用。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration//标注该类是Spring Boot主配置类
@EnableAutoConfiguration//开启自动配置功能
@ComponentScan(excludeFilters = {
   
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
   

}

1.@SpringBootConfiguration

        Spring Boot的配置类。标注在某个类上,表示这是一个Spring Boot的配置类。(该注解被@Configuration注解注释

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

}

        @Configuration 注解,又被@Component注解注释,说明 @SpringBootApplication注解其实也是Spring 容器的一个组件而已。(被@Component 注解注释的类,都是Spring 容器的组件)

@Target({
   ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
   
    String value() default "";
}

2.@EnableAutoConfiguration

        该注解意为:开启自动配置功能。以前我们需要配置的东西,开启该注解后,Spring Boot 便会帮我们自动配置(该注解被@ AutoConfigurationPackage注释)@AutoConfigurationPackage注解,意为:自动配置包()

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
//这是一个@Import
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
   

}

@AutoConfigurationPackage注解又被 @Import 注释,我们来继续分析 @Import 注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
//这是另一个@Import
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
   

}

        @Import 是 Spring 的一个底层注解,意思是:给容器中导入一个组件。先分析最里层 @Import 注解。该注解导入什么组件由AutoConfigurationPackages.Registrar这个类决定,这个类就是重点!!! 如下 new PackageImport(metadata).getPackageName()。这个方法就是重点内容!!!

@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
   

    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
   
        //此处 new PackageImport(metadata).getPackageName() 返回的是被 @SpringBootApplication 注解的类所在的包名。
        register(registry, new PackageImport(metadata).getPackageName());
    }

    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
   
        return Collections.<Object>singleton(new PackageImport(metadata));
    }

}

        new PackageImport(metadata).getPackageName();1.这个 @Import注解, 返回主配置类所在的包路径,然后通过 register() 方法,将该包下的所有配置信息,都加载到 Spring 容器中。 如下图所示:
在这里插入图片描述

        再来分析外层 @Import(EnableAutoConfigurationImportSelector.class) 注解。它导入的组件由EnableAutoConfigurationImportSelector这个类决定,该类继承自 AutoConfigurationImportSelector 类。这个类就是重点!!! 如下 selectImports() 方法,便是最终的执行方法。2.这个 @Import注解, 返回SpringBoot为我们默认配置的 AutoConfiguration。

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
   
    if (!isEnabled(annotationMetadata)) {
   
        return NO_IMPORTS;
    }
    try {
   
        AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                .loadMetadata(this.beanClassLoader);
        AnnotationAttributes attributes = getAttributes(annotationMetadata);
        //获取所有配置信息
        //分析getCandidateConfigurations方法,层层分析到loadSpringFactories()方法,最终发现
        //它会加载"META-INF/spring.factories"路径下的所有配置信息
        //getCandidateConfigurations,翻译为:获取候选人配置信息
        //configurations中的具体内容,如下图所示:
        List<String> configurations = getCandidateConfigurations(annotationMetadata,
                attributes);
        configurations = removeDuplicates(configurations);
        configurations = sort(configurations, autoConfigurationMetadata);
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        configurations = filter(configurations, autoConfigurationMetadata);
        fireAutoConfigurationImportEvents(configurations, exclusions);
        return configurations.toArray(new String[configurations.size()]);
    }
    catch (IOException ex) {
   
        throw new IllegalStateException(ex);
    }
}

META-INF/spring.factories 路径下的配置信息如下:
在这里插入图片描述
List<String> configurations 中加载的默认配置,具体内容如下图:
在这里插入图片描述
        Spring Boot 项目在启动的时候,会从类路径下的META-INF/spring.factories中获取 EnableAutoConfiguration 指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。这部分工作在 Spring 中我们都需要自己配置,Spring Boot 中的自动配置类都帮我们做了这些事情。J2EE的整体整合解决方案和自动配置都在 spring-boot-autoconfigure-x.x.x.RELEASE.jar这个包下。


分析结果:

        @SpringBootApplication 注解原理 主要通过两个@Import 注解,将配置的组件加载到 Spring 容器中,最终得以让 Spring 容器启动,其实底层还是通过 Spring 来实现的,你如果了解 Spring 容器底层实现,这块就会一目了然。

        ①会将 @SpringBootApplication 标注的主配置类,所在包及下面所有子包里面的所有组件扫描到 Spring 容器中;这个注解:@Import(AutoConfigurationPackages.Registrar.class)

        ②会将 SpringBoot 为 J2EE 企业级开发的默认配置,全部加载到 Spring 容器中。这个注解:@Import(EnableAutoConfigurationImportSelector.class)


博主写作不易,来个关注呗

求关注、求点赞,加个关注不迷路 ヾ(◍°∇°◍)ノ゙

博主不能保证写的所有知识点都正确,但是能保证纯手敲,错误也请指出,望轻喷 Thanks♪(・ω・)ノ

赞(0) 打赏
未经允许不得转载:IDEA激活码 » @SpringBootApplication注解分析

一个分享Java & Python知识的社区