@SpringBootApplication
作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;
这是一个组合注解,包含有以下几个注解:
@Target用来定义你的注解将应用于什么地方(例如是一个方法或者一个域)。
@ Retention用来定义该注解在哪一个级别可用,在源代码中(SOURCE)、类文件中(CLASS)或者运行时(RUNTIME)。
@Target:定义注解的作用目标(作用域)
@Target(ElementType.TYPE)
TYPE:接口、类、枚举、注解
FIELD:字段枚举的常量
METHOD:方法
PARAMETER:方法参数
CONSTRUCTOR:构造函数
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解
PACKAGE:包
TYPE_PARAMETER:参数类型声明
TYPE_USE:使用的类型
@Retention 注解有一个属性 value,是 RetentionPolicy 类型的,Enum RetentionPolicy 是一个枚举类型
这个枚举决定了 Retention 注解应该如何去保留,也可理解为 @Retention 搭配枚举类型 RetentionPolicy 使用。
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成 .class 文件的时候,被其标注的注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件中,但jvm加载 .class 文件时候,被其标注的注解会被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保留到 .class 文件中,jvm 加载 .class 文件之后,被其标注的注解仍然存在,
所以这个时候才可能通过反射机制读取注解的信息,而前两个生命周期中,通过反射机制读取不到注解信息的;
生命周期长度 RUNTIME > CLASS > SOURCE,所以后者能作用到的地方前者一定也能作用到,但是反过来,前者能作用到的地方后者就作用不到。
1、一般如果需要在运行时去动态获取注解信息,那只能用生命周期最长的 RUNTIME 标注了,比如 @Deprecated 就是使用 RetentionPolicy.RUNTIME 来标注的;
2、如果要在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife),就用 CLASS注解;
这个在源码中没有找到,但是参考其他博客写的 ButterKnife 就是被 RetentionPolicy.CLASS 标注的。
3、如果只是做一些检查性的操作,比如源码中的 @Override、@SuppressWarnings、@Native、@Generated 等就是被 RetentionPolicy.SOURCE 标注的。
@Documented
作用:生成文档信息的时候保留注解,对类作辅助说明
@Inherited
简单理解就是:如果使用了这个注解,那么该类的子类就不需要再写这个注解了,该类的子类会自动的继承这个注解
最常见的例子就是写单元测试时:我们有个@SpringBootTest的主单元测试类
一般我们新写一个单元测试时不需要再写注解,而是直接继承这个主单元测试类即可。
@Inherited是一个标识,用来修饰注解
作用:如果一个类用上了@Inherited修饰的注解,那么其子类也会继承这个注解
注意:
接口用上个@Inherited修饰的注解,其实现类不会继承这个注解
父类的方法用了@Inherited修饰的注解,子类也不会继承这个注解
当用了@Inherited修饰的注解的@Retention是RetentionPolicy.RUNTIME,则增强了继承性,在反射中可以获取得到
@ComponentScan
作用:自动扫描并加载符合条件的组件或者bean,并将这个bean定义加载到IOC容器中。
@SpringBootConfiguration
springboot的配置类,标注在某个类上,表示这是一个springboot的配置类
一直查看可知:
@Configuration
public @interface SpringBootConfiguration {}
@Component
public @interface Configuration {}
@Configuration:说明是一个配置类,配置类就是对应spring的xml的配置文件。
@Component :说明启动类就是一个spring的组件,负责启动应用
@EnableAutoConfiguration
开启自动装配功能,@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;
第一次点进去:
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
@AutoConfigurationPackage :自动配置包
@AutoConfigurationPackage继续点进去:
@Import({Registrar.class})
public @interface AutoConfigurationPackage {}
@Import({Registrar.class})
@import :Spring底层注解@import , 给容器中导入一个组件
Registrar.class 作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 ;
@Import({AutoConfigurationImportSelector.class})
给容器导入组件
AutoConfigurationImportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:
其中的关键就是spring.factories
打开spring.factories我们可以看到自动配置的文件了。
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。
总结:
-
SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
-
将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
-
整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
-
它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件,并配置好这些组件 ;
-
有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
SpringApplication.run分析
分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;
SpringApplication
这个类主要做了以下四件事情:
1、推断应用的类型是普通的项目还是Web项目
2、查找并加载所有可用初始化器 , 设置到initializers属性中
3、找出所有的应用程序监听器,设置到listeners属性中
4、推断并设置main方法的定义类,找到运行的主类
run方法流程分析: