自动装配简介
SpringBoot相比于其它框架(如SpringMVC等),最大的优势就是配置简单,易于操作,集成了大量类库,但却可以通过一个配置文件进行简单的操作。因此说SpringBoot的核心是自动装配也毫不为过,而SpringBoot的优势也在于自动装配,毕竟程序的发展的过程就是把手动的东西变成自动的,把复杂的东西变成简单的。
核心依赖
首先我们来思考一个问题,SpringBoot能够集成这么多复杂的东西,并且简化配置,首先它的依赖是在哪里导入的?
根据经验,打开pom.xml查看依赖,发现此文件中并没有想象中的大量依赖,但是有一个父工程,一路点过去果然发现了大量jar包的管理,因此可以得出SpringBoot的核心依赖都配置在父工程(spring-boot-dependencies)中。SpringBoot中导入依赖是不需要写版本信息的,所有版本信息都在父工程中配置好了。
资源过滤在spring-boot-starter-parent中,这三种配置文件类型也是SpringBoot主要配置类型。
yml使用方式传送门
启动器
在pom.xml下面存在一个个启动器,即SpringBoot的启动场景,SpringBoot会将一个个启动场景全部封装成启动器,需要使用什么只需要导入对应启动器即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-*</artifactId>
</dependency>
启动类
除了配置以外,启动一个单独的SpringBoot项目只需要一个启动类。
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
我们观察到这个启动类由一个注解(@SpringBootApplication)和一个启动方法(run)来构成。
@SpringBootApplication标注了这个类是一个SpringBoot应用,这个注解也是自动装配的关键。而run()方法则决定了SpringBoot项目怎么运行。
自动装配
去除以下四个基本注解,我们将自动装配的主线理一下。
@Target
用于描述注解的使用范围
@Retention
表示需要什么级别保存该注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
@Documented
说明该注解将被包含在javadoc中
@Inherited
说明子类可以继承父类中的该注解
SpringBoot自动装配流程如下
- 首先在spring-boot-autoconfigure-2.3.1.RELEASE.jar下面的META-INF/spring.factories中配置了大量的配置类,其中@EnableConfigurationProperties可以获取配置的反射对象,反射对象中的@ConfigurationProperties定义了配置的前缀,以及类中的属性组成的配置信息与resource中的配置文件可配置项一一对应。
- 在启动SpringBoot时会加载大量的配置类,通过导入AutoConfigurationImportSelector.class的反射对象,通过getCandidateConfigurations()方法获取所有配置项的List,并转化为properties供我们使用,getCandidateConfigurations()方法中调用SpringFactoriesLoader.loadFactoryNames()返回一个类加载器信息,而类加载器通过loadSpringFactories(classLoader)方法获取系统和项目参数,并放入缓存中,返回到List中。
- SpringBoot启动时会根据启动器的配置来动态的判断可使用配置,并将spring.factories中数据和配置文件一一绑定(yml/properties),从而达到配置文件自动装配的效果。
主启动类的运行
SpringBoot在启动时主要运行了一个SpringApplication.run(DemoApplication.class, args)方法,那么这个方法是怎么运行的呢?
SpringApplication类主要做了四件事情:
- 判断项目是普通项目还是web项目
- 查找并加载所有可用初始化器,设置到initializers属性中
- 找出所有应用程序监听器,设置到listeners属性中
- 推断并设置main方法的定义类,找到运行的主类
执行run()方法的时候会开启一个进程,进行一系列操作,即可访问。