一、简介
1.前置知识
- Java 17及以上版本
- Spring、SpringMVC、MyBatis
- Maven、IDEA
2.环境要求
环境&工具 | 版本(or later) |
SpringBoot | 3.0.5+ |
IDEA | 2021.2.1+ |
Java | 17+ |
Maven | 3.5+ |
Tomcat | 10.0+ |
Servlet | 5.0+ |
GraalVM Community | 22.3+ |
Native Build Tools | 0.9.19+ |
3.SpringBoot是什么
SpringBoot帮助开发者简单快速地创建一个独立的、生产级别的Spring应用
大多数SpringBoot应用只需要编写少量配置即可快速整合Spring平台以及第三方技术
特性:
- 快速创建独立Spring应用
- 直接嵌入Tomcat、Jetty or Undertow(无需部署war包)
- 提供可选的starter(场景启动器),简化应用整合
- 按需自动配置Spring以及第三方库
- 提供生产级特性:监控指标、健康检查(k8s)、外部化配置等
- 无代码生成、无xml
简化开发、简化配置、简化整合、简化部署、简化监控、简化运维。
4.场景案例
(1)开发流程
①创建项目(maven项目)继承spring-boot-starter-parent
<!-- 所有SpringBoot项目都必须继承自spring-boot-starter-parent -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.6</version>
</parent>
②导入场景依赖
<!-- web开发场景的启动器 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
③主程序启动应用
package com.pero.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 启动SpringBoot项目的主入口程序
*/
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class,args);
}
}
④编写业务
package com.pero.boot;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "hello,Springboot3!";
}
}
⑤测试
默认启动访问:127.0.0.1:8080
⑥打包
<!-- SpringBoot应用打包插件 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
mvn clean package 把项目打成可执行的jar包
java -jar demo.jar启动项目
(2)特性
①简化整合
导入相关场景,拥有相关功能。场景启动器
默认支持的所有场景:Developing with Spring Boot
官方提供的场景:命名为spring-boot-starter-*
第三方提供场景:命名为*-spring-boot-starter
②简化开发
无需编写任何配置直接开发业务
③简化配置
application.properties:集中管理配置
④简化部署
打包为可执行的jar包,linux服务器上有java环境即可
⑤简化运维
修改配置(外部放置一个application.properties文件)、监控、健康检查。
5.应用分析
(1)依赖管理机制
①开发什么场景导入什么场景启动器;maven以来传递规则,A-B-C:A就拥有B和C;导入场景启动器,场景启动器自动把这个场景所有核心依赖全部导入进来。
②每个Boot项目都有一个父项目Spring-boot-starter-parent;parent的父项目是Spring-boot-dependencies;父项目版本仲裁中心,把所有常见的jar的以来版本都声明好了。
③自定义版本号,利用maven的就近原则直接在当前项目pom文件下properties标签中声明父项目用的版本属性的key;直接在导入依赖的时候声明版本。
④第三方的jar包,boot父项目中没有管理的,需要自行声明。
(2)自动装配机制
①初步理解
- 自动配置Tomcat、SpringMVC等
- 以前:DispatcherServlet、ViewResolver、CharacterEncodingFilter...
- 现在:自动配置好组件
- 默认的包扫描规则
- @SpringBootApplication标注的类就是主程序类
- SpringBoot只会扫描主程序所在的包及其子包,自动的component-scan功能
- 自定义扫描路径
- @SpringBootApplication(scanBasePackages = "com.pero")
- @ComponentScan("com.pero")直接扫描指定路径
- 配置默认值
- 配置文件的所有配置项是和某个类的对象值进行一一绑定的。
- 绑定了配置文件中每一项值的类:属性类。例如ServerProperties绑定了所有Tomcat服务器有关的配置;MultipartProperties绑定了所有文件上传相关的配置。
- 按需加载
- 导入场景spring-boot-starter-web
- 场景启动器除了会导入相关功能依赖,导入一个spring-boot-starter,是所有starter的starter,基础核心starter
- spring-boot-starter导入了一个包spring-boot-autoconfigure。包里面都是各种场景的AutoConfiguration自动配置类
- 虽然全场景的自动配置都在spring-boot-autoconfigure这个包中,但是不是全部都开启的,导入那个场景就开启那个自动配置
②完整流程
导入starter-web:导入web开发场景
- 场景启动器导入了相关场景的所有依赖:starter-json、starter-tomcat、springMVC
- 每个场景启动器都引入了一个spring-boot-starter,核心场景启动器
- 核心场景启动器引入了spring-boot-autoconfigure包
- spring-boot-autoconfigure里面囊括了所有场景的所有配置
- 只要这个包下的所有类都能生效,那么相当于SpringBoot官方写好的整合功能就生效了
- SpringBoot默认却扫描不到spring-boot-autoconfigure下写好的所有配置类(这些票配置类给我们整合操作),默认值扫描主程序所在的包。
主程序:@SpringBootApplication
- @SpringBootApplication由三个注解组成@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
- SpringBoot默认值只能扫描自己主程序所在的包及其子包,扫描不到spring-boot-autoconfigure包中官方写好的配置类
- @EnableAutoConfiguration:SpringBoot开启自动配置的核心
- 是由@Import(AutoConfigurationImportSelector.class)提供功能,批量给容器导入组件。
- SpringBoot启动会默认加载142个配置类。
- 这142个配置类来自于spring-boot-autoconfigure下META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件指定
- 启动项目的时候利用@Import批量导入组件机制把autoconfigure包下的142个XxxxAutoConfiguration类导入进来(自动配置类)
- 虽然导入了142个自动配置类
- 按需生效:
- 并不是这142个自动配置类都能生效
- 每一个自动配置类都有条件注解@ConditionalOnXxxx,只有条件成立才能生效
③XxxxAutoConfiguration自动配置类
- 给容器中使用@Bean放一堆组件
- 每一个自动配置类都可能有@EnableConfigurationProperties(ServerProperties.class),用来把配置文件中的指定前缀的属性值封装到XxxxProperties属性类中
- 以Tomcat为例:把服务器的所有配置都是以server开头的,配置都封装到属性类中。
- 给容器中放的所有组件的一些核心参数都来自于XxxxProperties,XxxxProperties都是和配置文件绑定的
- 只需要改配置文件中的值,核心组件的底层参数都能够修改
④写业务,全程无需关心各种整合(底层将整合都写好了并且都生效了)
核心流程:
- 导入starter就会导入autoconfigure包
- autoconfigure包里面有一个文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.improts,里面指定的所有启动要加载的自动配置类
- @EnableAutoConfiguration会自动把上面文件里面写的所有自动配置类都导入进来,XxxxAutoConfiguration是有条件注解进行按需加载
- XxxxAutoConfiguration给容器中导入一堆组件,组件都是从XxxxProperties中提取属性值
- XxxxProperties又是和配置文件进行绑定。
效果:导入starter、修改配置文件,就能修改底层行为。
实践:
- 选场景,导入到项目
- 官方starter
- 第三方在maven仓库搜索
- 写配置,修改配置文件相关项目
- 数据库参数(链接地址,账号,密码...)
- 分析场景给我们导入那些能用的组件
- 自动装配这些组件进行后续使用
- 不满意boot提供的自动配好的默认组件
- 定制化
- 修改配置
- 自定义组件
- 定制化
整合Redis:
- 选场景:spring-boot-starter-data-redis
- 场景AutoConfiguration就是这个场景的自动配置类
- 写配置:
- 分析到这个场景的自动配置类开启了哪些属性绑定关系
- @EnableConfigurationProperties(RedisProperties.class)
- 修改redis相关配置
- 分析组件:
- 分析到RedisAutoConfiguration给容器中放了StringRedisTemplate
- 给业务代码中自动装配StringRedisTemplate
- 定制化
- 修改配置文件
- 自定义组件给容器中放一个StringTemplate
6.核心技能
(1)常用注解
SpringBoot摒弃XML配置方式,改为全注解驱动
①组件注册
@Configuration、@SpringBootConfiguration
@Bean、@Scope
@Controller、@Service、@Repository、@Component
@import
@ComponentScan
步骤:先@Configuration编写一个配置类,在配置类中,自定义方法给容器中注册组件。配合@Bean,或使用@Import导入第三方的组件
②条件注解
如果注解指定的条件成立,则触发指定行为
@ConditionalOnXxx
例如:@ConditionalOnClass:如果类路径中存在这个类,则触发指定行为;@ConditionalOnMissingClass:如果类路径中不存在这个类,则触发指定行为;@ConditionalOnBean:如果容器中存在这个Bean组件,则触发指定行为;@ConditionalOnMissingBean:如果容器中不存在这个Bean组件,则触发指定行为;
③属性绑定
@ConfigurationProperties:声明组件的属性和配置文件哪些前缀开始项进行绑定
@EnableConfigurationProperties:快速注册注解
场景:Springboot默认只扫描自己主程序所在的包,如果导入第三方包,即使组件上标注了@Component、@ConfigurationProperties注解也没用,因为组件扫描不进来。
将容器中任意组件(Bean)的属性值和配置文件的配置项的值进行绑定
给容器中注册组件(@Component、@Bean),使用@ConfigurationProperties声明组件和配置文件哪些配置项进行绑定
(2)Yaml文件
①基本语法
- 大小写敏感
- 使用缩进表示层级关系,k: v,使用空格分隔k,v
- 缩进时不允许使用Tab键,只允许使用空格
- 缩进的空格数目不重要,只要相同层级的元素左边对齐即可
- #表示注释,从这个字符一直到行尾都会被解析器忽略
支持写法:
- 对象:键值对的集合,例如:映射(map)/哈希(hash)/字典(dictionary)
- 数组:一组按次序排列的值,例如:序列(sequence)/列表(list)
- 纯量:单个的、不可分割的值,例如:字符串、数字、bool、日期
②示例
#properties
server.port=18080
spring.servlet.multipart.max-file-size=10MB
#Redis
spring.data.redis.host=localhost
spring.data.redis.port=6379
person.name=pero
person.age=28
person.birthday=1995/12/01 23:30:00
person.like=true
person.child.name=nano
person.child.age=1
person.child.birthday=2024/09/23 09:09:09
person.child.text[0]=abc
person.child.text[2]=def
person.dogs[0].name=小黑
person.dogs[0].age=3
person.dogs[1].name=小白
person.dogs[1].age=2
person.cats.c1.name=小花
person.cats.c1.age=1
#yml
server:
port: 18080
spring:
servlet:
multipart:
max-file-size: 10MB
data:
redis:
host: localhost
port: 6379
person:
name: pero
age: 18
birthday: 2010/02/22 12:12:12
like: true
child:
name: nano
age: 13
birthday: 2022/02/03 16:13:58
text:
- abc
- def
#text: ["abc","def"]
dogs:
- name: 小黑
age: 3
- name: 小白
age: 2
cats:
c1:
name: 小花
age: 1
c2: { name: 小灰,age: 2 }
③细节
- lineId推荐写为line-id
- 文本:
- 单引号不会转义【\n则为普通字符串显示】
- 双引号会转义【\n会显示为换行符】
- 大文本
- | 开头,大文本写在下层,保留文本格式,换行符正确显示
- > 开头,大文本写在下层,折叠换行符
- 多文档合并
- 使用---可以把多个yml文档合并一个文档中,每个文档区依然认为内容独立
(3)日志配置