简述springboot启动类中的@springBootApplication注解

时间:2024-10-02 07:12:31

关于springboot的启动类

在我们构建好一个springboot的项目后,我们可以看到一个springboot的启动类,大概是这个样子的。

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

从代码中可以我们可以看到这个启动类中也就两行代码。但是浓缩的往往都是精华。

@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}
)}
)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

从源码中我们可以看到主要是三个注解在起作用
@ComponentScan
@EnableAutoConfiguration
@SpringBootConfiguration

@ComponentScan

源码

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
........
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这个注解的作用是 指定扫描包的位置 如果没有制定,那么会默认是该类同级目录下的所有包

@EnableAutoConfiguration

源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "";

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

    String[] excludeName() default {};
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

该注解也是一个复合注解,其作用主要是:开启自动配置

如何开启自动配置

从源码中我们看到有个注解——@Import({})
这个注解加载了AutoConfigurationImportSelector 类,类中的selectImports方法,根据返回的String数组(配置类的Class的名称)加载配置类。
到这里可能会有一个疑问,Import只是导入了这个类,但是并没有调用
selectImports这个方法,那么是如何加载配置类的呢?主要是在run的方法中调用了selectImports方法。

如果我们继续往下会发现加载的并不是只有我们指定扫描包下的类,也会有其他的类,那么其他的类是如何加载的呢?
#loadSpringFactories 源码

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/");
                。。。。。。。。。
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

其他的类主要是通过 META-INF/ 这个文件来加载到springboot的容器中的。

@SpringBootConfiguration

源码

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

该注解与 @Configuration注解的作用是一致的,也就是标记当前的类为配置类,当前类下如果有@Bean之类的注解,也会被加载到springboot的容器中。

总结

@springBootApplication注解是一个复合注解,主要有三个注解发挥了作用
@ComponentScan 指定扫描包
@EnableAutoConfiguration 加载配置类
@SpringBootConfiguration 标记当前类为配置类

后续有时间,会把源码仔细的肝一遍,了解的更加清楚。有兴趣的朋友可以关注我,一起肝