Spring Boot实战:从0开始动手搭建企业级项目
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

5.3 @SpringBootApplication注解与分析

Spring Boot项目的大部分配置和代码写法都和日常开发的项目相同。开发人员甚至可以直接将一些代码直接复制到Spring Boot项目中直接使用。唯一比较明显的区别就是在Spring Boot项目目录结构中多了一个主程序类Application.class。

那么这个主程序类是做什么的呢?查看代码如下:

由这部分代码能够看出,与普通的Spring项目对比,二者的区别在@SpringBootApplication注解和启动方法SpringApplication.run()上。因为未使用Spring Boot开发的Java Web项目既没有@SpringBootApplication注解也没有启动方法。

笔者在这一节将结合源码对主程序类进行分析讲解,揭开Spring Boot的神秘面纱。

5.3.1 @SpringBootApplication注解

按住Ctrl键并点击@SpringBootApplication注解,查看其源码:

由注解源码可以看出,@SpringBootApplication注解是一个复合注解,其中前面四个注解是Java元注解,含义分别如下所示。

@Target(ElementType.TYPE):类、接口(包括注解类型)和enum声明。

@Retention(RetentionPolicy.RUNTIME):运行时注解。

@Documented:将注解添加到Java doc中。

@Inherited:允许继承。

重要的是后面三个注解,含义分别如下所示。

@SpringBootConfiguration:Spring Boot配置注解。

@EnableAutoConfiguration:启用自动配置注解。

@ComponentScan:组件自动扫描注解。

Java元注解并无特殊含义,这里可以将@SpringBootApplication注解理解为@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan这三个注解的组合注解。如果在主程序类中不使用@SpringBootApplication注解的话,也可以在主程序类上直接标注@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan这三个注解,其效果也是一样的,如下所示:

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

5.3.2 @SpringBootConfiguration注解

@SpringBootConfiguration注解的源码如下所示:

查看该段代码可以发现,类上声明了@Configuration注解。这个Spring自定义注解读者应该很熟悉,它是从Spring 3版本开始就存在的注解,主要用于定义配置类,替代XML配置文件。

@SpringBootConfiguration注解仅仅是对@Configuration注解进行了包装,本质上依然是@Configuration注解。@SpringBootConfiguration注解是1.4版本中新增的注解,标注在某个类上表示这是一个Spring Boot的配置类。

5.3.3 @EnableAutoConfiguration注解

@EnableAutoConfiguration注解表示开启自动配置功能。自动配置是Spring Boot最为核心的一个特性,也是“约定大于配置”设计思想的主要体现。而@EnableAuto Configuration注解就是这个功能的入口。

@EnableAutoConfiguration注解的源码如下所示:

除Java元注解以外,这个注解最重要的就是@AutoConfigurationPackage注解和使用@Import注解引入的AutoConfigurationImportSelector组件。

5.3.4 @AutoConfigurationPackage源码解析

@AutoConfigurationPackage注解的源码如下所示:

该注解中包含Spring框架的@Import注解,其作用就是将标注了该注解的组件注册到Spring的IOC容器中,而导入的内容则由AutoConfigurationPackages. Registrar.class类指定。也就是说Spring Boot会注册自动配置包的名称,默认为当前主程序类所在的包及其子包。这些包中的组件会被加载到容器中。

需要注意的是,加载到其他包中的组件默认是不会被扫描的。这也是为什么有的开发人员在配置了组件后无法被加载的原因。比如本次演示的项目,NewbeeMallApplication主程序类所在的目录是根目录,其包名为“ltd.newbee.mall”,所以在该包及子包下的组件都会被扫描进来。如果新建一个“ltd.newbee.demo”包,Spring Boot项目在启动时demo包中的组件是无法被加载到Spring IOC容器中的。

“默认为当前主程序类所在的包及其子包”这个结论并不是猜测。接下来笔者结合源码来解释这个结论,读者可以根据以下步骤来验证。

(1)在IDEA中打开org.springframework.boot.autoconfigure.AutoConfigurationPackages类。在代码的第124行打上一个断点。

(2)点击右上角工具栏中的启动按钮,注意,一定要点击右侧的按钮,以debug方式启动项目。

(3)启动后会在register()方法上阻塞,此时选中new PackageImports(metadata). getPackageNames().toArray(new String[0])并点击右键出现工具栏,点击“Evaluate Expression”,可以获取该表达式的最终结果,如图5-3所示。

图5-3 debug方式获取默认扫描包

整个debug过程如图5-4所示,最终得出的结果为“ltd.newbee.mall”,即“默认会扫描当前主程序类所在的包及其子包”。

图5-4 debug方式获取默认扫描包结果

5.3.5 EnableAutoConfigurationImportSelector类的源码解析

EnableAutoConfigurationImportSelector类是整个自动配置功能的核心实现,它负责把返回自动配置的相关组件名称注册至IOC容器中,源码及源码解释如下所示:

其中,getCandidateConfigurations()方法会调用SpringFactoriesLoader类的loadFactoryNames()获取所有的自动配置类的类名,源码如下所示:

AutoConfigurationImportSelector会将所有需要导入的组件以全类名的方式返回,这些组件就会被注册到IOC容器中。

由以上源码可以得出结论:Spring Boot在启动的时候从类路径META-INF/spring. factories中获取EnableAutoConfiguration指定的配置项,在过滤后将这些值作为自动配置类导入容器中。

有哪些自动配置类呢?

可以在spring-boot-autoconfigure-2.3.7.RELEASE.jar依赖中查看。点击项目目录中的“External Libraries”可以看到所有依赖jar包,点开“Maven:org.springframework. boot:spring-boot-autoconfigure:2.3.7.RELEASE”,就能够看到“META-INF/spring.factories”文件,如图5-5所示。

图5-5 META-INF/spring.factories文件

spring.factories文件内容如下所示:

spring.factories文件的org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项定义的就是Spring Boot默认加载的所有自动配置类。不过,这些自动配置类在项目启动时并不会全部被执行,因为每个自动配置类是否正常执行有对应的条件。以org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration自动配置类为例,如果pom.xml文件中没有引入spring-boot-starter-web,那么该自动配置类就不会工作。这是因为缺少相应的jar包和依赖,自动配置无法生效,其他自动配置类同理。

除了org.springframework.boot.autoconfigure.EnableAutoConfiguration配置项,spring.factories文件中还有org.springframework.context.ApplicationContextInitializer、org. springframework.context.ApplicationListener等配置项,这些都是Spring Boot重要的组成部分。

在自动配置类被执行时,Spring Boot会启动相关组件和类的自动装配工作。以往需要开发人员在XML文件中手动配置的内容都由Spring Boot完成,从而免去了手动编写配置、注入相应功能组件等工作。

5.3.6 @ComponentScan注解

使用Spring框架开发Java Web项目的读者一定都用过@Controller、@Service、@Repository等注解。查看其源码会发现,在这些注解的定义上都会标注一个共同的注解@Component。而在Spring IOC容器中@Controller、@Service、@Repository、@Component等注解的默认装配标识是@ComponentScan注解。

在普通的Spring项目开发中,一般会在Spring配置文件中编写如下配置,将对应包下的所有组件扫描并注册到容器中:

使用注解的方式与这种XML配置文件的方式所实现的效果是相同的。@ComponentScan注解的作用就是让Spring容器从对应包下获取需要注册的类。开发人员通过注解来定义哪些包需要被自动扫描并装配。一旦指定了相应的包名,Spring将会在被指定的包及其子包中寻找标注了以上注解的Bean并注册到容器中。