SpringBoot
Spring Boot
配置文件
默认配置文件
放在src/main/resources下,名称必须为application.yml
使用环境变量
1 | |
日志配置文件
名称为logback-spring.xml,用来定义日志级别、日志格式、日志输出位置
1 | |
不同环境下的配置
最上面的为默认配置,通过---隔开不同环境的配置
1 | |
在idea中通过添加虚拟机参数
-Dspring.profiles.active=环境名指定环境在命令行通过
java -Dspring.profiles.active=环境名 -jar xxx.jar指定环境不指定环境名时为
default
读取配置
通过@Value注解一个个读取配置
1 | |
通过@ConfigurationProperties一次性读取多个配置
1 | |
打包项目
通过spring-boot-maven-plugin插件来打包
1 | |
mvn clean:只清理,不构建mvn package:直接打包,但不会删除旧文件mvn clean install:清理 + 构建 + 把包安装到本地仓库(~/.m2/repository),方便别的项目依赖mvn clean deploy:清理 + 构建 + 部署到远程仓库mvn clean package:打包项目打包完项目会在
target/目录下生成xxx.jar(包含依赖)和xxx.jar.original(不包含依赖)可通过
java -jar xxx.jar直接运行
常用注解
启动类上
@SpringBootApplication:启动Spring Boot应用程序,标注在启动类上
注解包含了
@SpringBootConfiguration:本质上就是@Configuration,表示这是一个配置类@EnableAutoConfiguration:开启自动配置,会根据项目中的 classpath 依赖 和 定义的配置,自动配置 Spring 应用所需要的 Bean@ComponentScan:负责扫描Bean,默认会扫描启动类所在包及其子包下的组件
@EnableTransactionManagement:开启事务管理
@Transactional@MapperScan:MyBatis 项目里常用,指定 Mapper 接口包路径
@ComponentScan:指定扫描的包,自动发现并注册组件
@Import:显式导入类/配置到容器
配置类上
@Configuration:声明当前类是一个配置类,配合
@Bean使用@Bean:用于方法上,把返回值对象交给 Spring 容器管理
方法的返回值就是要注册到容器中的对象,默认 Bean 名称是方法名
@Lazy:bean 会在第一次使用才创建方法的参数会被容器解析,相当于
@Autowired自动注入@Conditional:条件装配,根据条件判断是否加载这个Bean
@ConditionalOnClass:某个类存在时才生效@ConditionalOnMissingBean:容器里没有某个 Bean 时才加载@ConditionalOnProperty:配置文件里存在某属性时才生效
….
@ConfigurationProperties:把配置文件里的属性绑定到类的属性里
@Profile:只在指定环境下加载Bean
监控运行状态
Actuator 是 Spring Boot 提供的一个监控和管理工具。它可以暴露 应用运行状态、指标、健康信息、日志级别动态修改等 端点(Endpoints)。对生产环境运维和监控非常有用
引入依赖
1
2
3
4<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>添加配置
1
2
3
4
5
6
7# Actuator会把它能收集到的所有信息都暴露给JMX,出于安全原因,只会把health和infoo暴露给Web
# 可以设置Web能访问的端点
management:
endpoints:
web:
exposure:
include: info, health, beans, env, metrics访问
1
http://localhost:8080/actuator/health
使用过滤器
1.实现Filter接口
可以重写Filter中的三个方法
| name | 说明 |
|---|---|
| init(FilterConfig) | 创建filter时会调用一次 |
| doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) | 拦截客户端请求时调用 |
| destroy() | 销毁filter时会调用一次 |
2.注册拦截器
方式1: 注解注册
通过@WebFilter(filterName, urlPatterns)注解来说明这是一个过滤器
| 参数 | 说明 |
|---|---|
| filterName | 过滤器名字 |
| urlPatterns | 拦截的路径 |
然后在主启动类上使用@ServletComponentScan注解开启扫描
加上这个注解可以扫描@Servlet、@Filter、@Listener
方式2: 配置类方式注入
1 | |
例子
1 | |
自定义异常处理器
案例
自定义异常类
基础异常类
1
2
3
4
5
6
7
8
9
10
11
12
13
14@Data
public class BaseException extends Exception{
private final Integer code;
public BaseException(Integer code, String message) {
super(message);
this.code = code;
}
public BaseException(ResultStatus status) {
super(status.getDescription());
this.code = status.getCode();
}
}根据业务场景派生不同异常
1
2
3
4
5
6
7
8/**
* 用户权限异常
*/
public class UnauthorizedException extends BaseException{
public UnauthorizedException(String message) {
super(ResultStatus.UNAUTHORIZED.getCode(), message);
}
}
添加全局异常处理类
添加
@RestControllerAdvice注解来统一捕获所有异常@RestControllerAdvice=@ControllerAdvice+@ResponseBody1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理自定义业务异常
@ExceptionHandler(BaseException.class)
public CommonResult<?> handleBaseException(BaseException e) {
return CommonResult.fail(e.getCode(), e.getMessage());
}
// 处理空指针等运行时异常
@ExceptionHandler(NullPointerException.class)
public CommonResult<?> handleNullPointerException(NullPointerException e) {
return CommonResult.fail(500, "空指针异常");
}
// 处理所有其他异常
@ExceptionHandler(Exception.class)
public CommonResult<?> handleException(Exception e) {
return CommonResult.fail(500, "服务器内部错误: " + e.getMessage());
}
}业务代码中抛出异常
1
2
3
4
5
6
7
8@GetMapping("/test")
public CommonResult<String> test() throws BaseException {
if(true) {
throw new BaseException(666, "testException");
}
return CommonResult.success("test");
}
Http请求工具
RestClient
在Spring Boot 3.2之后,使用RestClient代替RestTemplate进行发送Http请求
基本使用
导入依赖
1
2
3
4
5# 包含在了Spring Boot Web依赖中
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>添加
RestClientConfig配置类1
2
3
4
5
6
7
8
9
10
11
12
13@Configuration
public class RestClientConfig {
/**
* 全局 RestClient Bean
*/
@Bean
public RestClient restClient(Builder builder) {
return builder
.defaultHeader("User-Agent", "MyApp/1.0 (SpringBoot 3.3.5)") // 通用 header
.baseUrl("http://localhost:5050") // 第三方 API 地址
.build();
}
}测试
1
2
3
4
5
6
7
8
9@Test
public void test() {
// 往body()里传将Json反序列化后的对象的.class。 记得该类要有getter、setter和构造方法
Map<String, Object> body = restClient.get()
.uri("/version")
.retrieve()
.body(String.class);
System.out.println(body);
}
Spring Boot Starter
预先包含了所需的依赖以及配置
为什么需要
例如要使用Mybatis,需要手动引入 MyBatis、Spring-JDBC、数据库驱动等多个依赖。之后还要写相关配置及注入Bean,写不好还会出现版本冲突。
而使用mybatis-spring-boot-starter就能自动完成上面的操作
命名规范
- 官方的:
spring-boot-starter-xxx - 非官方的:
xxx-spring-boot-starter
Starter结构
xxx-starter(启动器包)
只做管理依赖,就是一个空壳 pom,把该场景所有需要的 jar 都依赖进来
xxx-starter-autoconfigure(自动配置包)
存放自动配置类、配置属性类、META-INF 配置文件
SpringBoot 启动时会自动扫描META-INF 配置文件,把里面的配置类加载到容器
demo
新建一个demo-spring-boot-starter-demo项目
demo-spring-boot-starter-autoconfigure
在
pom.xml内引入依赖1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 关键:删除了 parent,改用 dependencyManagement -->
<groupId>com.xw</groupId>
<artifactId>demo-spring-boot-starter-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-spring-boot-starter-autoconfigure</name>
<description>demo-spring-boot-starter-autoconfigure</description>
<properties>
<java.version>17</java.version>
</properties>
<!-- 只管理版本,不做可执行项目 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>4.0.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 配置属性绑定 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- 自动配置核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
</dependencies>
</project>自动配置
创建一个类用于注入测试,
com/demo/starter/service/DemoHelloService.java1
2
3
4
5
6
7
8
9
10
11
12
13package com.demo.starter.service;
public class DemoHelloService {
private String name;
private String msg;
public String sayHello() {
return "【自定义Starter】" + name + " : " + msg;
}
public void setName(String name) { this.name = name; }
public void setMsg(String msg) { this.msg = msg; }
}创建
com/demo/starter/props/DemoProperties.java来读取配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15package com.demo.starter.props;
@ConfigurationProperties(prefix = "demo.hello")
public class DemoProperties {
// 配置 demo.hello.name=xxx
private String name = "默认名称";
// 配置 demo.hello.msg=xxx
private String msg = "默认消息";
// getter / setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getMsg() { return msg; }
public void setMsg(String msg) { this.msg = msg; }
}创建
com/demo/starter/config/DemoAutoConfiguration.java来自动配置并注入Bean1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package com.demo.starter.config;
// 开启属性绑定
@EnableConfigurationProperties(DemoProperties.class)
@Configuration
public class DemoAutoConfiguration {
// 容器中没有 DemoHelloService 才自动创建
@Bean
@ConditionalOnMissingBean
public DemoHelloService demoHelloService(DemoProperties properties) {
DemoHelloService service = new DemoHelloService();
service.setName(properties.getName());
service.setMsg(properties.getMsg());
return service;
}
}创建
resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports用于依赖注入1
com.demo.starter.config.DemoAutoConfigurationmvn clean install
demo-spring-boot-starter
引入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.14</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xw</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo-spring-boot-starter</name>
<description>demo-spring-boot-starter</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- 只依赖自动配置模块 -->
<dependency>
<groupId>com.xw</groupId>
<artifactId>demo-spring-boot-starter-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>mvn clean install
创建测试项目
引入依赖
1
2
3
4
5<dependency>
<groupId>com.xw</groupId>
<artifactId>demo-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>添加配置
1
2
3
4demo:
hello:
name: "张三"
msg: "自定义Starter测试成功"注入
DemoHelloService测试1
2
3
4
5
6
7
8
9
10
11@RestController
public class TestController {
@Autowired
private DemoHelloService demoHelloService;
@GetMapping("/hello")
public String hello() {
return demoHelloService.sayHello();
}
}
原理
扫描自动配置类
启动项目时,Spring Boot 利用 SpringFactoriesLoader 去扫描应用类路径下所有 JAR 包里的特殊配置文件META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
装载自动配置类
之后根据条件装配来选择要实例化的类
@ConditionalOnClass:当类路径下存在某个类时才生效。@ConditionalOnMissingClass:缺少某类时生效。@ConditionalOnBean:当容器中已有某个 Bean 时/不在时生效。@ConditionalOnProperty:当配置文件中某个属性有指定值时生效等等。
自动配置类里的Bean会被注入到容器里