SpringBoot项目通常有一个*Application的入口类,这个类里面有main方法即项目的主方法,启动项目,在入口类上有一个注解 @SpringBootAppliaction 此注解就是SpringBoot项目的核心注解。通过学习此注解可以了解SpringBoot项目运行的基本原理。
注解@SpringBootApplication是SpringBoot的核心注解,也是一个组合注解,如下:
@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 {
先理解两个概念:组合注解和元注解
组合注解:被注解的注解,即有多个注解组合成的注解,此注解就具备了组合它的注解的功能
元注解:可以注解到别的注解上的注解,即用于修饰注解的注解
我们可以看到@SpringBootApplication注解是由多个注解组合而成,其中@Target、@Retention、@Document、@Inherited为元注解。java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。
可以简单了解一下这四个元注解
@Target
用于描述注解的范围,即注解在哪用。它说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)等。取值类型(ElementType)有以下几种:
CONSTRUCTOR:用于描述构造器
FIELD:用于描述域即类成员变量
LOCAL_VARIABLE:用于描述局部变量
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述参数
TYPE:用于描述类、接口(包括注解类型) 或enum声明
TYPE_PARAMETER:1.8版本开始,描述类、接口或enum参数的声明
TYPE_USE:1.8版本开始,描述一种类、接口或enum的使用声明
@Retention
用于描述注解的生命周期,表示需要在什么级别保存该注解,即保留的时间长短。取值类型(RetentionPolicy)有以下几种:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在运行时有效(即运行时保留)
@Document
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。它是一个标记注解,没有成员。
@Inherited
用于表示某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
我们可以发现@SpringBootApplication注解除了四个元注解外还有@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan注解
首先 @SpringBootConfiguration 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
除了元注解外剩余@Configuration,此注解我们相对比较熟悉,@Configuration注解用在某个类上表示这个类是配置类,项目启动时就加载,并且将此类注入到Spring容器中,所以我们也就会想到入口类*Application其实也是一个配置类,项目启动装配。
接下来 @EnableAutoConfiguration 注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@EnableAutoConfiguration注解开启自动配置,是@SpringBootApplication的核心功能。
@AutoConfigurationPackage是项目中所有的包注册。
而@EnableAutoConfiguration最重要的是引入AutoConfigurationImportSelector将所有符合条件的@Configuration配置加载到IOC容器中,借助Spring的工具类SpringFactoriesLoader扫描具有META-INF/spring.factories文件的jar包,并将其注入
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
例如spring-boot-autoconfigure-2.1.8RELEASE.jar其中包含META-INF/spring.factories文件,在此jar包中就包含着我们常用到的SpringBoot已经集成的组件。比如:aop、jdbc、cache、web、thymeleaf等等,所以我们在使用SpringBoot特别方便,SpringBoot已经帮我们集成了跟多需要的组件。有兴趣可以看一下这个jar包。
最后 @ComponentScan 注解
@ComponentScan也是熟悉的注解,Spring通过@ComponentScan注解启动扫描,@ComponentScan有一个属性basePackages可以设置要扫描的基础包,注意基础包路径为全路径,当然可能你注意到了basePackages是一个复数,所以可以配置多个基础包,若只配置一个基础包,可以省略basePackages;若不配置基础包,那么扫描的是配置类当前的包以及其子包。所以SpringBoot入口类与基本包同一级,因此@ComponentScan可以扫描到项目中所有的包,并且将添加了@Component注解的类注入到IOC容器中,类似Spring框架中如下操作:
@Configuration
@ComponentScan( "com.cxd.javaweb.service")
public class ComponentConfig {
}