Spring Boot 概述及自动装配原理(基于3.x更新)
spring boot 简介
SpringBoot 帮我们简单、快速地创建一个独立的、生产级别的 Spring 应用(例如微服务应用,详细参照 微服务详细介绍(中文),微服务详细介绍(英文)),可以说springboot是框架中的框架,大多数 SpringBoot 应用只需要编写少量配置即可快速整合 Spring 平台以及第三方技术。其实可以使用单反相机和傻瓜相机来类比spring 和 springboot 的关系,一个springboot项目你只需要简单地 ”按一下快门“ 就能快速构建出来。如果需要深度定制,则需要深度理解springboot的自动装配原理。
快速搭建一个应用
首先我们来感受一下sb构建一个应用到底有多简单。参考 文档
1) 创建maven工程

1 |
|
2) 配置文件 src/main/resources/application.properties(或者ymal)
配置文件的所有配置项是和某个类的对象值进行一一绑定的。绑定了配置文件中每一项值的类被称为属性类。spring 官方提供了一系列支持的参数和属性类,例如ServerProperties 绑定了所有Tomcat服务器有关的配置,MultipartProperties 绑定了所有文件上传相关的配置,这部分可以参考:官方提供的 Application Properties、官方提供的 Server Properties
1 | server: |
3) 编写启动类
1 | import org.springframework.boot.SpringApplication; |
4) 编写相关的Controller、Service
1 | import org.springframework.stereotype.Controller; |
5) 开发环境启动应用
1 | # 直接使用 eclipse 或 idea 工具启动主程序类 |
6) 部署应用
这个maven插件可以将应用打包成一个可执行的jar包,参考 文档
1 | <build> |
打包部署和运行项目
1 | $ mvn clean package -Dmaven.test.skip=true |
[新增] 关于使用 maven-assembly-plugin 插件组织项目结构,请参考 使用-assembly-打生产包。
SB核心原理-自动装配
请读者自己思考一下:SpringBoot怎么实现导一个 starter 、写些简单配置,应用就能跑起来?为什么Tomcat的端口号可以配置在 application.properties 中,并且 Tomcat 能启动成功?

自动配置流程细节梳理
第一:根据业务导入需要的场景 starter,比如 spring-boot-starter-web
- 场景启动器导入了相关场景的所有依赖: starter-json 、 starter-tomcat 、 springmvc
- 几乎每个场景启动器都引入了 spring-boot-starter,它是SB的核心场景启动器(它是starter中的starter)。
- 核心场景启动器引入了 spring-boot-autoconfigure 包,其中囊括了几乎所有场景的所有配置。
- 只要这个包下的所有类都能生效,那么相当于SpringBoot官方写好的整合功能就生效了。
- SB默认只扫描主程序及其子孙路径下的组件,是扫不到 spring-boot-autoconfigure 下写好的所有配置类的。
第二,从主程序 @SpringBootApplication 来分析
- @SpringBootApplication 由三个注解组成 @SpringBootConfiguration 、 @EnableAutoConfiguration、 @ComponentScan。
- SpringBoot 默认只能扫描自己主程序所在的包及其下面的子孙包,扫描不到 spring-boot-autoconfigure 包中官方写好的配置类。
- @EnableAutoConfiguration 是 SpringBoot 开启自动配置的核心。它由 @Import(AutoConfigurationImportSelector.class) 提供功能,批量给容器中导入组件。项目启动的时候SB 会利用 @Import 批量导入组件机制把 spring-boot-autoconfigure 包下 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件指定的100多个 XxxAutoConfiguration 类导入进来。这100多个 XxxAutoConfiguration 类虽然被导入了,但是这个配置中定义的 Bean 基本都是被 @ConditionalOnXxx 注解的,只有满足条件的Bean才能注册到spring工厂,本质上它们都是按需加载。
第三,我们再来看这些被加载的 XxxAutoConfiguration 自动配置类
- 这些配置类 XxxAutoConfiguration 基本都是用 @Bean 给容器中放一堆相关的组件。
- 每个自动配置类都可能使用注解 @EnableConfigurationProperties(XxxProperties.class) ,把配置文件中配的指定前缀的属性值封装到 XxxProperties 属性类中。以Tomcat为例,对应的属性配置类是 ServerProperties(该类被 @ConfigurationProperties(“server”) 修饰 ),其配置都是以 server 开头的,这些属性值都被封装在了 ServerProperties 中。这些 XxxProperties 完成了配置文件的参数和应用组件的绑定。
- 开发者只需要改配置文件的值,核心组件的底层参数都能修改,全程无需关心各种整合(底层这些整合写好了,而且也生效了)。
使用 starter 的最佳姿势
第一,选择所需的场景starter,导入到项目
- 官方 starter,命名一般是 spring-boot-starter-xxx,可以参考 springboot starters
- 第三方的 stater,命名一般是 xxx-spring-boot-starter
第二,根据 XxxAutoConfiguration 的 XxxProperties 写配置,改配置文件关键项
- 例如数据库参数(连接地址、账号密码…)
第三,根据 XxxAutoConfiguration 分析这个starter场景给我们导入了哪些能用的组件
- 自动装配这些组件进行后续使用
- 不满意boot提供的自动配好的默认组件可以进行深度定制化(改配置或者自定义组件)
以整合redis为例:
- 选场景: spring-boot-starter-data-redis,场景 RedisAutoConfiguration 就是这个场景的自动配置类
- 写配置:
- 分析自动配置类开启了哪些属性绑定关系 @EnableConfigurationProperties(RedisProperties.class)
- 根据这个绑定的属性配置类来修改redis相关的配置
- 分析组件:
- 分析到 RedisAutoConfiguration 给容器中放了哪些bean,如 StringRedisTemplate
- 给业务代码中自动装配 StringRedisTemplate
- 定制化:
- 修改配置文件
- 自定义组件,自己给容器中放一个 StringRedisTemplate
常用注解
组件注册注解
- @SpringBootApplication、@ImportResource(locations = {“classpath:x.xml”})、@Import(XComponent.class)
- @Configuration(≈@SpringBootConfiguration)、@Bean、@Scope、@ComponentScan
- @Controller、 @Service、@Repository、@Component
组件注册的条件注解
@ConditionalOnXxx :如果注解指定的条件成立,则触发指定行为。如果放在方法上,则单独判断这个方法;如果放在类上,则是 判断这个配置配是否生效。
@ConditionalOnClass:如果类路径中存在这个类,则触发指定行为
@ConditionalOnMissingClass:如果类路径中不存在这个类,则触发指定行为
@ConditionalOnBean:如果容器中存在这个Bean(组件),则触发指定行为
@ConditionalOnBean(value=组件类型,name=组件名字):判断容器中是否有这个类型的组件,并且名字是指定的值
@ConditionalOnMissingBean:如果容器中不存在这个Bean(组件),则触发指定行为
1 | // 检查类路径Classpath下是否存在某个类,或者某个文件资源。 |
属性绑定注解
例如下面配置文件 src/main/resources/person.properties
1 | person.last-name=zhang\nsan |
或 person.ymal 文件形式
1 | # 细节 |
对应的属性配置类:
1 |
|
1 |
|
如果上述Person类没有标注 @Component 或使用 @Bean new 对象将其放到容器,也可以在配置类上标注 @EnableConfigurationProperties({Person.class, Person2.class}) 将其注入到容器中。@EnableConfigurationProperties 典型的场景是用于第三方组件的属性绑定。
日志配置
Spring使用commons-logging作为内部日志,但底层日志实现是开放的,也可对接其他日志框架。spring5及以后 commons-logging 被 spring直接封装了。Spring 支持 jul、log4j2、logback,提供了默认的控制台输出配置,也可以配置输出为文件。虽然日志框架很多,但是我们不用担心,使用 SpringBoot 的默认配置就能工作的很好。
日志的自动装配
- 每个 starter 场景,都会导入一个核心场景 spring-boot-starter
- 核心场景引入了日志的所用功能 spring-boot-starter-logging
- 默认使用了 logback + slf4j 组合作为默认底层日志
- 日志是系统一启动就要用 , 而 XxxAutoConfiguration 是系统启动好了以后放好的组件,所以日志stater是不存在 XxxAutoConfiguration 的。
- 日志是利用监听器机制配置好的,ApplicationListener 。
- 日志所有的配置都可以通过修改配置文件实现,它是以 logging 开始的所有配置。
日志依赖的切换
1 | <dependency> |
日志的全局配置
日志分组:将相关的 logger 分组在一起,统一配置。比如:Tomcat 相关的日志统一设置。
1 | logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat |
日志级别:由低到高 ALL, TRACE, DEBUG, INFO, WARN, ERROR ,FATAL, OFF。不指定级别的所有类,都使用root指定的级别作为默认级别。SpringBoot 日志默认级别是 INFO。
1 | # 在application.properties/yaml中配置 |
文件归档与滚动切割:
- 归档:每天的日志单独存到一个档中。
切割:每个文件10MB,超过切割成另外个件。
logging.file.name 和 logging.file.path:如果两者均未指定则仅仅控制台输出;若都指定则以 logging.file.name 为准。
- logging.logback.rollingpolicy.file-namepattern:日志存档的文件名格式(默认值: ${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz)。
- logging.logback.rollingpolicy.clean-historyon-start:应用启动时是否清除以前存档(默认值: false)。
- logging.logback.rollingpolicy.max-file-size:存档前,每个日志文件的最大大小(默认值: 10MB)。
- logging.logback.rollingpolicy.total-size-cap:日志文件被删除之前,可以容纳的最大大小(默认值:0B)。设置1GB则磁盘存储超过 1GB 日志后就会删除旧日志文件。
- logging.logback.rollingpolicy.max-history:日志文件保存的最大天数(默认值:7)。
我们建议的最佳实战是:自己要写配置,配置文件名加上 xx-spring.xml:
- Logback:logback-spring.xml, logback-spring.groovy, logback.xml, or logback.groovy
- Log4j2:log4j2-spring.xml or log4j2.xml
- JDK (Java Util Logging):logging.properties
如果可能,我们建议您在日志配置中使用 -spring 变量(例如, logback-spring.xml 而不是 logback.xml )。如果您使用标准配置文件,spring 无法完全控制日志初始化。
日志的最佳实战
- 导入任何第三方框架,先排除它的日志包,因为Boot底层控制好了日志。
- 修改 application.properties 配置文件,就可以调整日志的所有行为。如果不够,可以编写日志框架自己的配置文件放在类路径下就行,比如 logback-spring.xml , log4j2-spring.xml。
- 如需对接专业日志系统,也只需要把 logback 记录的日志灌倒 kafka 之类的中间件,这和 SpringBoot 没关系,都是日志框架自己的配置,修改配置文件即可。
- 业务中使用slf4j-api记录日志。不要再 sout 了。