1. spring-boot-starter
决定一个项目是否为SpringBoot项目的关键是看是否集成了spring-boot-starter-parent。
1.1 spring-boot-starter-parent
spring-boot-starter-parent中提前配置好了常见第三方组件的版本号,方便直接引用,若遇到需要指定版本的场景,推荐使用如下方法指定版本:
- 查询spring-boot-depedencies中该依赖的标签名;
- 在当前项目中重写该配置项。
1.2 starter的一些默认配置
SpringBoot提供了大量的官方starter,供开发者使用,其命名方式spring-boot-starter-,若要自定义starter,官方推荐命名为-spring-boot-starter
无论是官方starter还是第三方starter,都要依赖于spring-boot-starter,而starter的自动装配核心依赖是spring-boot-autoconfigure。
SpringBoot提供了大量的开发场景下的默认配置,以达到快速开发的目的。例如:
- SpringBoot默认扫描启动类所造包下的所有注解,注册成为bean
- SpringBoot默认servlet请求中的上传文件的最大大小是1MB
- ……
这些配置的值最终都会映射到某一个类上,这些类都会被注册为bean。
2. 一些核心注解
2.1 @Configuration
带有@Configuration注解的类可以看做是原生Spring中的xml配置文件,每一个带有@Bean的方法都相当于是注册了一个bean,bean名称默认是方法名,可以通过name属性指定。
proxyBeanMethods
proxyBeanMethods属性是配置类中较为重要的属性,也是SpringBoot实现Full/Lite模式的关键属性。
proxyBeanMethods含义是设置配置类是否启用代理模式,默认为true。true模式下,每次调用配置类中返回bean的方法时,都会先去容器中查找是否有当前实例,保证了实例的单例性,此时就称为Full模式;当proxyBeanMethods为false时,配置类不会开启代理模式,每次调用配置类中的方法获取bean,不进行判断,直接创建一个新的实例并返回,此时就是Lite模式。
俩种模式的选取建议:当配置类中的Bean没有被其他组件依赖时,使用Lite模式,加快容器启动速度,减少判断;当配置类中的bean被依赖时,使用Full模式。
2.2 @Import
@Import用于手动注册bean到容器中,可以添加到@SpringBootApplication(启动类)、@Configuration(配置类)、@Component(组件类)上。
1 | {XXX1.class, XXX2.class} |
2.3 @Conditional
@Conditional含义是条件装配,Spring中提供了很多派生注解来满足不同场景下的条件装配,例如:
- @ConditionalOnBean(name=”xxx”) 当容器中存在指定名称的bean实例时,注册当前bean
- @ConditionalOnMissingBean (name=”xxx”) 当容器中不存在指定名称的bean实例时,注册当前bean
- @ConditionalOnWarDeployment 当项目为war包部署时,注册当前bean
- @ConditionalOnProperty 当存在某个参数时候,注册当前bean
- ……
2.4 @ImportResource
@ImportResource的作用是解析原生spring中的xml配置文件,导入其中的配置信息
1 |
2.5 @ConfigurationProperties
2.5.1 @Component+@ConfigurationProperties
@ConfigurationProperties的作用是将核心配置文件配置文件中的配置信息绑定到bean中的属性,该注解只能使用在被容器管理的bean上
1 |
|
2.5.2 @EnableConfigurationProperties+@ConfigurationProperties
大多数场景下,SpringBoot回避免直接在某个类上加@Component注解,这时就需要第二种获取配置信息的注解,在某个类上加@ConfigurationProperties注解用于接收配置信息,在另外一个配置类上加@EnableConfigurationProperties并且指定刚刚的参数映射类,可以达到一样的效果,SpringBoot底层大量使用了这种方式,例如kafka自动配置:
1 |
|
3. 自动装配原理入门
由源码可知,@SpringBootApplication是一个合成注解,其中包含的三个核心注解,实现了自动装配的功能。
1 |
3.1 @SpringBootConfiguration
源码可知,@SpringBootConfiguration其内部就是一个@Confiuration配置类,并且设置了proxyBeanMethods默认值为true;
3.2 @ComponentScan
包扫描注解的高级用法,引入了SpringBoot中俩个自定义的扫描器,完成了包扫描的设置。
3.3 @EnableAutoConfiguration
@EnableAutoConfiguration是实现自动装配最核心的注解,也是一个合成注解,其内部是:
1 |
3.3.1 @AutoConfigurationPackage
@AutoConfigurationPackage内部:
1 |
而Registrar源码如下
1 |
|
这段代码的实际含义就是找到主启动类所在的包,扫描这个包下的所有注解,完成bean注册。
3.3.2 @Import({AutoConfigurationImportSelector.class})
引入AutoConfigurationImportSelector类,最终的导入逻辑落到了这段代码:
1 | result = new HashMap<>(); |
由此可知,SpringBoot在启动时会扫描所有jar包下的META-INF/spring.factories文件,加载其中的配置信息,关键在于spring-boot-autoconfigure-2.6.3.jar中的META-INF/spring.factories文件,这个文件中有一段配置:
1 | # Auto Configure |
所以,综上所述,SpringBoot做的事其实就是将J2EE开发所以用到的所有解决方案整合到spring-boot-autoconfigure-2.6.3.jar中的META-INF/spring.factories文件中,SpringBoot在容器启动时,会加载这个文件中所有配置,但是查看autoconfigure包中的源码可以发现,其中所有的配置类都是条件装配(@Conditional),这样,只要导入了对应的starter,容器就会帮我们完成自动配置。
由autoconfigure包中的源码可知,SpringBoot会在底层做好所有的配置,但如果用户配置了自己的实例,则以用户的优先。
总结:
SpringBoot启动时会加载所有的自动配置类(XXXAutoConfiguration),
每个自动配置类会按条件进行注册,大部分配置类还会关联外部的配置项,所以SpringBoot整合的组件都可以从application.properties中获取配置信息。由此,SpringBoot既完成了自动装配,按需加载的容器实现,又极大地简化了开发配置。