一、前言
大部分的配置都可以用Java类+注解来代替,而在SpringBoot项目中见的最多的莫过于@SpringBootApplication注解了,它在每个SpringBoot的启动类上都有标注。
这个注解对SpringBoot的启动和自动配置到底有什么样的影响呢?本文将为各位大佬解析它的源码,揭开@SpringBootApplication注解神秘的面纱。
二、正文
对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 {
...
}
可以看到这是一个复合注解,一共包括7个不同的注解,下面对这7个不同的注解进行分析。
2.1 注解
2.1.1 注解1:@Target({ElementType.TYPE})
用来表示注解作用范围,TYPE表示作用范围为类或接口。
2.1.2 注解2:@Retention(RetentionPolicy.RUNTIME)
2.1.3 注解3:@Documented
表明这个注释是由 javadoc记录的。
2.1.4 注解4:@Inherited
放在注解上,当父类加了@SpringBootApplication注解时,子类也会继承这个注解(对接口的实现类无效)。
2.1.5 注解5:@SpringBootConfiguration
底层仍是@Configuration注解, 源码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
2.1.6 注解6:@ComponetScan
@ComponentScan这个注解在Spring中很重要,它对应XML配置中的元素@ComponentScan的功能其实就是自动扫描并加载符合条件的组件(比如@Component和@Repository等)或者bean定义,最终将这些bean定义加载到IoC容器中。
可以通过basePackages等属性来细粒度的定制@ComponentScan自动扫描的范围,如果不指定,则默认Spring框架实现会从声明@ComponentScan所在类的package进行扫描。所以SpringBoot的启动类最好是放在root package下,因为默认不指定basePackages。
2.2 注解:@EnableAutoConfiguration
个人感觉@EnableAutoConfiguration这个Annotation最为重要它的作用可以概括为:借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器。
其源码如下:
@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 {};
}
这里需要关注@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)两个注解。
2.2.1 注释:@AutoConfigurationPackage
源码如下:
@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 {};
}
可以发现这个注解的核心其实也是Import注解,表示对于标注该注解的类的包,应当使用AutoConfigurationPackages注册。接着看Registrar这个类:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
//metadata是我们注解所在的元信息
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//将我们注解所在包下所有的组件进行注册
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
这个类中的核心方法是register方法:
private static final String BEAN = AutoConfigurationPackages.class.getName();
public static void register(BeanDefinitionRegistry registry, String+]X]\\
Y]Y]K\[YJ
CB
[]Y
\][˙[YJ[YJH
N]\]X]\BCBOB]BoUKRS[˙XY\+y.[XP]]Y][k9aj:fd9kd#y`fy[Y{Y]PY][&B]\HHBH\H\]NBXY\[Y]PY][[][Y]Y]HY]Y]K[][]X]\]X]\\[Y][H[XY\\XS[Y\[XY\\XP\
KBX[\\
JN\\[\JY][]]Y][\\[QUKRS[˙XY\Y[B
\H\HXYXZH][H\XN]\Y][BCBXY\[XY\\XP\
H]\[XP]]Y][\CBOB]Bam.+{[XY\\XS[Y\z/*y9/g9+*9kb:/oyfj9.UKRS[˙XY\oykgkk9aj:fd9kd#{Bc&Bo :)yfi9d#{/*[XP]]Y][+zacyBK)9.*f";Bg :)yfi9fi;B.ykX[][\][hy.c:/"9"yam:-iy.)"{Bno#9o]Y][[\\[\`9"ykd#$9.c9no&BKg :)z(cyd9fi9k9aj:fd9kd#yl z($9.]]Y][[ykhz/ Bfi;[XP]]Y][c9cey...\]9.+y'9k`9"yQUKRS[˙XY\k#9nml!am.+Q[XP]]Y][k9acyhnz`&/!9k/.k9!Y][[kyfj:acynmb:/oyb,[kyfj8B."xl#BB`&/"b!9c[Л\X[:/g9+[X[Y][h#(ncy.#:(][YX[^9jmb'yi%[j8B`&/[XP]]Y][iyj#:/mb:/oy`:g :)y.&\[[jm9`9"y!\[9cmkd99/9alyd#:/g9k.[9m"):acy B."l,y+[Л\X[9/o:+yk{&al[Л\X[9/o:-a9z+l/c.amkl O |