Skip to content

Spring Boot 完整入门教程:从入门到精通 ​

写给读者的话:

这不是一篇"Hello World"式的浅尝辄止的教程。

这篇教程会带你从最基础的概念开始,一路深入到 Spring Boot 的核心原理、各种技术选型对比、前沿技术趋势,以及企业级开发中的硬核实践。

你会看到大量的对比分析(技术选型怎么选)、原理剖析(为什么是这样)、实用技巧(工作中直接能用)和前沿趋势(未来的方向)。

适合谁读:

  • 有 Java 基础,想系统学习 Spring Boot 的同学
  • 已经在用 Spring Boot,但想深入理解原理的开发者
  • 想了解 Spring 生态全貌、做技术选型的架构师
  • 准备面试,需要系统性梳理知识的求职者

怎么读:

  • 新手:按顺序读,先建立整体认知
  • 有基础:挑感兴趣的章节深入看
  • 面试前:重点看对比、原理、最佳实践部分

准备好了吗?我们开始。


目录 ​


第 1 章:为什么是 Spring Boot ​

1.1 Java Web 开发的进化史 ​

要理解 Spring Boot 为什么火,得先看看 Java Web 开发是怎么一步步进化的。

第一阶段:Servlet + JSP(远古时代)

  • 写 Servlet,继承 HttpServlet,重写 doGet/doPost
  • 配置 web.xml,每个 Servlet 配一个
  • JSP 写页面,里面嵌 Java 代码
  • 部署到 Tomcat,启动慢,配置多
  • 问题:配置繁琐、开发效率低、项目结构混乱

第二阶段:SSH 框架时代(Struts + Spring + Hibernate)

  • Struts 处理 Web 层
  • Spring 管理 Bean,IOC/AOP
  • Hibernate 操作数据库
  • 问题:配置还是很多,Struts 漏洞多,Hibernate 不够灵活

第三阶段:SSM 时代(Spring + SpringMVC + MyBatis)

  • SpringMVC 替代 Struts
  • MyBatis 替代 Hibernate,SQL 更灵活
  • Spring 贯穿始终
  • 问题:还是要写一堆 XML 配置,依赖管理麻烦,整合各种框架费时费力

第四阶段:Spring Boot 时代(现在)

  • 约定优于配置,开箱即用
  • 起步依赖,不用自己找版本
  • 内嵌容器,不用装 Tomcat
  • 自动配置,不用写一堆 XML
  • starter 生态,整合各种技术就加个依赖
  • 问题:入门容易精通难,出了问题不好排查

第五阶段:Spring Cloud + Spring Boot(微服务时代)

  • 基于 Spring Boot 的微服务全家桶
  • 服务注册发现、配置中心、网关、熔断...
  • 问题:复杂度高,运维成本高

简单说:Spring Boot 就是把以前 Spring 开发需要的各种配置、整合、部署工作都给你简化了。 以前搭一个 Spring 项目要一天,现在 5 分钟搞定。

1.2 Spring Boot 到底是什么 ​

官方定义:Spring Boot 是 Spring 家族的一个子项目,目的是简化 Spring 应用的初始搭建和开发过程。

人话翻译:

  • 不是新框架,是 Spring 的"加速器"
  • 把 Spring 全家桶整合好了,拿来就能用
  • 自动配置了很多东西,不用你手动配
  • 内嵌 Tomcat/Jetty/Undertow,直接 JAR 包运行
  • 提供 starter 依赖,加一个依赖就整合一种技术

核心特性:

特性说明
起步依赖Starter 依赖,自动管理版本
自动配置自动配置 Spring 应用
内嵌容器内嵌 Tomcat,直接 java -jar 运行
Actuator生产级监控和管理
无代码生成不用生成代码,纯配置
无 XML 配置不用写 XML,全注解

1.3 Spring Boot vs 传统 Spring 开发 ​

维度传统 Spring 开发Spring Boot
依赖管理手动找依赖,版本冲突常踩坑Starter 起步依赖,自动管理版本
配置方式大量 XML 配置自动配置 + 少量注解
部署方式打 WAR 包,部署到外部 Tomcat打 JAR 包,内嵌容器直接运行
开发效率搭项目半天起步5 分钟搞定一个项目
学习曲线陡峭,要学各种配置平缓,开箱即用
灵活性高,什么都能自己配中,默认配置够用,要改也能改
问题排查配置都在明面上自动配置是黑盒,出问题不好找

Spring Boot 不是替代 Spring,而是在 Spring 之上做了一层封装。 你可以理解为:Spring 是零件,Spring Boot 是组装好的整机。

1.4 Spring Boot 能做什么 ​

Spring Boot 几乎能做所有 Java 后端开发的事情:

领域说明
Web 应用网站、后台管理系统、RESTful API
微服务配合 Spring Cloud 做微服务
企业应用OA、CRM、ERP 等管理系统
数据处理批处理、ETL、数据清洗
移动端后端App、小程序的 API 服务
物联网IoT 设备管理、数据采集
游戏后端游戏服务器、匹配系统

简单说:只要是 Java 后端,Spring Boot 基本都能做。 而且是现在 Java 后端的绝对主流。

1.5 版本选择指南 ​

Spring Boot 版本很多,怎么选?

版本JDK 要求Spring 版本状态推荐
2.7.x8 ~ 185.3.x开源维护结束老项目维护用
3.0.x17 ~ 196.0.x已停止维护不推荐
3.1.x17 ~ 206.0.x已停止维护不推荐
3.2.x17 ~ 216.1.x开源维护中推荐学习用
3.3.x17 ~ 226.1.x最新稳定版新项目首选

选择建议:

  • 学习/新项目:选最新稳定版(3.3.x),用 JDK 17+
  • 老项目维护:看项目用的什么版本,保持一致
  • 企业选型:选 LTS(长期支持)版本,更稳定

注意:Spring Boot 3.x 要求 JDK 17+,而且用的是 Jakarta EE 命名空间(javax → jakarta)。 从 2.x 升级到 3.x 不是无缝的,有一些迁移工作。


第 2 章:快速入门 ​

2.1 环境准备 ​

必备工具:

工具推荐版本说明
JDK17+Spring Boot 3.x 要求 17+
Maven3.8+构建工具
IDEIDEA 旗舰版开发效率神器
数据库MySQL 8.0+最常用的关系型数据库
Redis7.0+缓存
Postman / Apifox最新版接口测试

可选工具:

  • Docker:容器化部署
  • Git:版本控制
  • Navicat / DBeaver:数据库可视化
  • JMeter:压测

2.2 创建项目的三种方式 ​

方式一:Spring Initializr(官方推荐)

  1. 打开 https://start.spring.io/
  2. 选择项目信息(Group、Artifact、Java 版本)
  3. 选择依赖(Web、MyBatis、Redis...)
  4. 下载 ZIP,解压,用 IDEA 打开

方式二:IDEA 内置(最方便)

  1. IDEA → New Project → Spring Initializr
  2. 填信息,选依赖
  3. 一键创建,自动下载依赖

方式三:Maven 手动创建(了解原理)

  1. 创建 Maven 项目
  2. pom.xml 加 parent 和 starter 依赖
  3. 写启动类
  4. 写配置文件

新手推荐用 IDEA 内置的方式,最方便。 手动创建的方式了解一下就行,知道原理。

2.3 第一个 Spring Boot 项目 ​

pom.xml 核心依赖:

xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.2</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

启动类:

java
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

第一个 Controller:

java
@RestController
public class HelloController {
    
    @GetMapping("/hello")
    public String hello() {
        return "Hello Spring Boot!";
    }
}

启动,访问:http://localhost:8080/hello

就这么简单!一个 Web 项目就跑起来了。 以前要配 Tomcat、配 Spring MVC、写 web.xml,现在什么都不用配。

2.4 项目结构解读 ​

src/main/java
└── com/example/demo
    ├── DemoApplication.java      # 启动类(项目入口)
    ├── controller/               # 控制层(接收请求)
    ├── service/                  # 业务层(业务逻辑)
    ├── mapper/                   # 数据访问层(操作数据库)
    ├── entity/                   # 实体类(数据库表对应)
    ├── dto/                      # 数据传输对象(前后端传参)
    ├── config/                   # 配置类
    ├── common/                   # 公共类
    ├── exception/                # 异常处理
    └── utils/                    # 工具类

src/main/resources
├── application.yml               # 配置文件
├── static/                       # 静态资源(js、css、图片)
└── templates/                    # 模板页面(Thymeleaf 等)

src/test/java                     # 测试代码

三层架构:

  • Controller 层:接收请求,参数校验,返回结果
  • Service 层:业务逻辑,事务控制
  • Mapper/DAO 层:数据访问,操作数据库

这是企业项目最经典的分层结构,一定要掌握。 分层的目的是解耦,各层各司其职,好维护。

2.5 开发必备插件 ​

IDEA 插件推荐:

插件作用
Lombok简化实体类,不用写 getter/setter
MyBatisXMyBatis 代码生成,Mapper 跳转
Rainbow Brackets彩虹括号,代码更清晰
Translation翻译插件,看英文文档方便
Json ParserJSON 格式化
RestfulToolkit接口搜索、测试
Maven HelperMaven 依赖分析、冲突解决

好的工具能让开发效率翻倍。 不要觉得用插件是投机取巧,工具就是用来提高效率的。


第 3 章:核心原理深度剖析 ​

3.1 @SpringBootApplication 注解揭秘 ​

很多人以为 @SpringBootApplication 是一个普通注解,其实它是一个组合注解。

java
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
    // ...
}

三个核心注解:

注解作用
@SpringBootConfiguration标记这是一个配置类,其实就是 @Configuration
@EnableAutoConfiguration开启自动配置,Spring Boot 的核心
@ComponentScan组件扫描,自动扫描并注册 Bean

就这一个注解,干了三件大事。 这就是 Spring Boot 开箱即用的秘密之一。

3.2 自动配置原理(硬核) ​

自动配置是 Spring Boot 最核心的功能,也是最神秘的。

自动配置到底是怎么工作的?

第一步:@EnableAutoConfiguration

这个注解导入了一个选择器:AutoConfigurationImportSelector

第二步:加载自动配置类

AutoConfigurationImportSelector 会去 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件里读取所有自动配置类的全限定名。

Spring Boot 内置了 100+ 个自动配置类,比如:

  • DataSourceAutoConfiguration(数据源自动配置)
  • WebMvcAutoConfiguration(Web MVC 自动配置)
  • RedisAutoConfiguration(Redis 自动配置)
  • ...

第三步:条件装配

不是所有自动配置类都会生效,每个配置类上都有条件注解:

java
@Configuration
@ConditionalOnClass(DataSource.class)           // 类路径下有 DataSource 才生效
@ConditionalOnMissingBean(DataSource.class)     // 容器中没有 DataSource 才生效
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
    // ...
}

常用条件注解:

注解作用
@ConditionalOnClass类路径下有指定类才生效
@ConditionalOnMissingClass类路径下没有指定类才生效
@ConditionalOnBean容器中有指定 Bean 才生效
@ConditionalOnMissingBean容器中没有指定 Bean 才生效
@ConditionalOnProperty配置文件中有指定属性才生效
@ConditionalOnWebApplicationWeb 应用才生效
@ConditionalOnNotWebApplication不是 Web 应用才生效

第四步:绑定配置属性

自动配置类会绑定配置文件中的属性,通过 @ConfigurationProperties。

比如数据源配置:

yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

这些属性会绑定到 DataSourceProperties 类上,然后自动配置类用这些属性来创建 DataSource Bean。

总结一下自动配置流程:

启动 → @EnableAutoConfiguration → 加载所有自动配置类
→ 条件装配(满足条件的才生效)→ 绑定配置属性 → 创建 Bean → 放入容器

自动配置的本质:约定 + 条件装配 + 属性绑定。 约定好了默认配置,你不配置就用默认的,你配置了就用你的。

怎么看哪些自动配置生效了?

启动时加参数:--debug,或者配置:

yaml
debug: true

启动日志里会打印:

  • Positive matches:生效的自动配置
  • Negative matches:没生效的自动配置
  • Exclusions:排除的自动配置

遇到自动配置的问题,先开 debug 看看哪些生效了,哪些没生效,为什么没生效。 这是排查自动配置问题的利器。

3.3 起步依赖原理 ​

起步依赖(Starter)是什么?

简单说:就是一个 pom.xml,把某个场景需要的依赖都打包好了。

比如 spring-boot-starter-web 里面包含了:

  • spring-web
  • spring-webmvc
  • jackson-databind
  • spring-boot-starter-tomcat
  • ...

你只需要加一个 starter-web 依赖,这些就都有了,不用自己一个个加,也不用担心版本冲突。

版本管理:

版本是怎么管理的?靠 parent。

spring-boot-starter-parent 里面定义了几百个依赖的版本号,你加依赖不用写版本号,直接用 parent 里的。

这样做的好处:

  • 不用自己找版本
  • 不会有版本冲突
  • 升级 Spring Boot 版本,所有依赖版本一起升

Starter 不是什么黑科技,就是 Maven 的依赖传递 + 版本管理。 但这个设计真的很巧妙,大大降低了依赖管理的复杂度。

3.4 内嵌容器原理 ​

Spring Boot 为什么能直接 java -jar 运行?

因为它把 Tomcat 内嵌进去了。

原理:

  1. 启动时,Spring Boot 检查是不是 Web 应用
  2. 如果是,就创建一个内嵌的 Tomcat/Jetty/Undertow
  3. 把 DispatcherServlet、Filter 等注册到内嵌容器
  4. 启动容器

怎么切换容器:

xml
<!-- 排除 Tomcat,换成 Jetty -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

三种容器对比:

容器特点适用场景
Tomcat最常用,稳定,生态好大多数场景
Jetty轻量,灵活,内存占用小内存敏感、嵌入式场景
Undertow高性能,非阻塞 IO,轻量高并发、性能要求高

一般项目用 Tomcat 就行,稳定可靠。 追求性能或者内存敏感的场景可以考虑 Undertow 或 Jetty。

3.5 Spring Boot 启动流程 ​

Spring Boot 启动过程是怎样的?简单梳理一下:

1. 执行 main 方法,调用 SpringApplication.run()
2. 创建 SpringApplication 对象
3. 准备环境(加载配置文件、profile 等)
4. 打印 Banner
5. 创建 ApplicationContext(容器)
6. 注册 Bean 定义
7. 执行各种初始化器
8. 刷新容器(Bean 实例化、自动配置等)
9. 执行 CommandLineRunner、ApplicationRunner
10. 启动完成,打印启动时间

启动过程中的扩展点:

扩展点作用
ApplicationContextInitializer容器刷新前执行
BeanFactoryPostProcessorBean 定义加载后,实例化前
BeanPostProcessorBean 实例化前后
CommandLineRunner启动完成后执行
ApplicationRunner启动完成后执行(参数更丰富)
@PostConstructBean 初始化后执行
InitializingBeanBean 属性设置完后执行

了解启动流程和扩展点,能帮你更好地定制 Spring Boot 的行为。 比如启动时做一些初始化工作,就可以用 CommandLineRunner。


第 4 章:Web 开发全景 ​

4.1 Spring MVC 自动配置 ​

Spring Boot 自动配置了 Spring MVC,开箱即用。

自动配置的内容:

  • DispatcherServlet:前端控制器
  • HandlerMapping:处理器映射
  • HandlerAdapter:处理器适配器
  • ViewResolver:视图解析器
  • Converter:类型转换器
  • Validator:数据校验
  • 静态资源映射
  • 文件上传支持
  • 异常处理
  • ...

什么都不用配,直接就能用。

4.2 RESTful API 设计 ​

RESTful 是现在最流行的 API 设计风格。

核心原则:

  • 资源用 URI 表示
  • 用 HTTP 方法表示操作
  • 用 HTTP 状态码表示结果
  • 无状态

HTTP 方法对应 CRUD:

方法操作幂等示例
GET查询是GET /users(查列表)、GET /users/1(查单个)
POST新增否POST /users(新增用户)
PUT修改(全量)是PUT /users/1(修改用户 1)
PATCH修改(部分)否PATCH /users/1(部分修改用户 1)
DELETE删除是DELETE /users/1(删除用户 1)

HTTP 状态码:

状态码含义场景
200 OK成功查询、修改成功
201 Created创建成功新增成功
204 No Content无内容删除成功
400 Bad Request请求参数错误参数校验失败
401 Unauthorized未认证没登录
403 Forbidden无权限登录了但没权限
404 Not Found资源不存在路径错了或资源不存在
409 Conflict冲突重复创建
500 Internal Server Error服务器内部错误代码异常

RESTful 是一种风格,不是强制标准。 实际项目中不用教条,怎么方便怎么来。 但基本的规范还是要遵守的,前后端协作更顺畅。

4.3 参数绑定大全 ​

Spring MVC 支持多种参数绑定方式:

1. 路径参数

java
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    // ...
}

2. 请求参数(Query String)

java
@GetMapping("/users")
public List<User> listUsers(@RequestParam(defaultValue = "1") int page,
                            @RequestParam(defaultValue = "10") int size) {
    // ...
}

3. 请求体(JSON)

java
@PostMapping("/users")
public User createUser(@RequestBody @Valid UserDTO userDTO) {
    // ...
}

4. 表单参数

java
@PostMapping("/login")
public String login(@RequestParam String username, 
                    @RequestParam String password) {
    // ...
}

5. 请求头

java
@GetMapping("/test")
public String test(@RequestHeader("Authorization") String token) {
    // ...
}

6. Cookie

java
@GetMapping("/test")
public String test(@CookieValue("JSESSIONID") String sessionId) {
    // ...
}

7. Model/Map

java
@GetMapping("/test")
public String test(Model model) {
    model.addAttribute("name", "张三");
    return "view";
}

8. 原生 API

java
@GetMapping("/test")
public void test(HttpServletRequest request, 
                 HttpServletResponse response) {
    // ...
}

参数绑定方式很多,根据场景选择。 最常用的是 @PathVariable、@RequestParam、@RequestBody。

4.4 数据校验(JSR-303) ​

参数校验是必须的,不能相信前端传过来的任何数据。

常用校验注解:

注解作用
@NotNull不能为 null
@NotEmpty不能为 null 且不能为空(字符串、集合)
@NotBlank不能为 null 且不能全是空格
@Min最小值
@Max最大值
@Size大小范围
@Email邮箱格式
@Pattern正则匹配
@Valid级联校验

使用示例:

java
@Data
public class UserDTO {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 3, max = 20, message = "用户名长度 3-20")
    private String username;
    
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度 6-20")
    private String password;
    
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
}

Controller 中使用:

java
@PostMapping("/users")
public R<User> createUser(@RequestBody @Valid UserDTO userDTO, 
                          BindingResult result) {
    if (result.hasErrors()) {
        // 校验失败,返回错误信息
        return R.error(result.getFieldError().getDefaultMessage());
    }
    // ...
}

全局异常处理校验异常:

不用每个方法都写 BindingResult,全局统一处理:

java
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<String> handleValidationException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return R.error(message);
    }
}

校验一定要做,而且后端校验不能省。 前端校验是为了用户体验,后端校验是为了安全。 永远不要相信前端传过来的数据。

4.5 统一返回结果 ​

所有接口返回统一格式,前端好处理。

java
@Data
public class R<T> {
    private int code;       // 状态码
    private String message; // 提示信息
    private T data;         // 数据
    private long timestamp; // 时间戳
    
    public static <T> R<T> success(T data) {
        R<T> r = new R<>();
        r.setCode(200);
        r.setMessage("success");
        r.setData(data);
        r.setTimestamp(System.currentTimeMillis());
        return r;
    }
    
    public static <T> R<T> error(int code, String message) {
        R<T> r = new R<>();
        r.setCode(code);
        r.setMessage(message);
        r.setTimestamp(System.currentTimeMillis());
        return r;
    }
}

统一返回结果是企业项目的标配。 前端不用每个接口写一套解析逻辑,统一处理就行。

4.6 全局异常处理 ​

所有异常统一处理,不用每个方法都 try-catch。

java
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    // 业务异常
    @ExceptionHandler(BusinessException.class)
    public R<Void> handleBusinessException(BusinessException e) {
        return R.error(e.getCode(), e.getMessage());
    }
    
    // 参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Void> handleValidationException(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldError().getDefaultMessage();
        return R.error(400, msg);
    }
    
    // 其他异常
    @ExceptionHandler(Exception.class)
    public R<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return R.error(500, "系统异常,请联系管理员");
    }
}

全局异常处理 + 自定义业务异常 = 优雅的错误处理。 代码里遇到业务错误直接抛异常,不用层层返回。

4.7 静态资源 ​

Spring Boot 自动配置了静态资源映射。

默认静态资源位置(优先级从高到低):

  1. classpath:/META-INF/resources/
  2. classpath:/resources/
  3. classpath:/static/
  4. classpath:/public/

访问方式:直接访问文件名,比如 classpath:/static/img/logo.png → http://localhost:8080/img/logo.png

自定义静态资源路径:

yaml
spring:
  web:
    resources:
      static-locations: classpath:/static/,file:/data/static/

4.8 文件上传下载 ​

文件上传:

java
@PostMapping("/upload")
public R<String> upload(MultipartFile file) throws IOException {
    String originalFilename = file.getOriginalFilename();
    String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
    String filename = UUID.randomUUID() + suffix;
    
    file.transferTo(new File("/data/upload/" + filename));
    return R.success(filename);
}

文件下载:

java
@GetMapping("/download/{filename}")
public void download(@PathVariable String filename, 
                     HttpServletResponse response) throws IOException {
    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition", 
        "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));
    
    Files.copy(Paths.get("/data/upload/" + filename), 
               response.getOutputStream());
}

配置上传大小:

yaml
spring:
  servlet:
    multipart:
      max-file-size: 10MB      # 单个文件最大
      max-request-size: 100MB  # 整个请求最大

文件上传下载是 Web 项目的常见功能。 注意:生产环境文件不要存在应用服务器上,要用对象存储(OSS、COS 等)。

4.9 跨域问题(CORS) ​

前后端分离项目一定会遇到跨域问题。

什么是跨域:

  • 协议不同(http vs https)
  • 域名不同
  • 端口不同

只要有一个不同,就是跨域。

解决方案:

方式一:全局配置(推荐)

java
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
}

方式二:注解方式

java
@CrossOrigin(origins = "*")
@RestController
public class UserController {
    // ...
}

方式三:过滤器方式

java
@Bean
public CorsFilter corsFilter() {
    // ...
}

推荐用全局配置的方式,一次配置所有接口都生效。 注意:生产环境不要允许所有来源,要配置具体的域名。

4.10 拦截器 ​

拦截器可以在请求处理前后做一些事情,比如登录校验、权限检查、日志记录。

定义拦截器:

java
@Component
public class LoginInterceptor implements HandlerInterceptor {
    
    // 请求处理前
    @Override
    public boolean preHandle(HttpServletRequest request, 
                             HttpServletResponse response, 
                             Object handler) throws Exception {
        // 检查登录状态
        Object user = request.getSession().getAttribute("user");
        if (user == null) {
            response.setStatus(401);
            return false;  // 拦截
        }
        return true;  // 放行
    }
    
    // 请求处理后,视图渲染前
    @Override
    public void postHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler, 
                           ModelAndView modelAndView) throws Exception {
        // ...
    }
    
    // 整个请求完成后
    @Override
    public void afterCompletion(HttpServletRequest request, 
                                HttpServletResponse response, 
                                Object handler, 
                                Exception ex) throws Exception {
        // ...
    }
}

注册拦截器:

java
@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private LoginInterceptor loginInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")          // 拦截所有
                .excludePathPatterns(            // 排除这些
                    "/login",
                    "/register",
                    "/public/**"
                );
    }
}

拦截器 vs 过滤器:

维度过滤器 Filter拦截器 Interceptor
规范Servlet 规范Spring MVC 规范
执行时机请求到达 Servlet 之前Controller 前后
能拿到的东西只有 request/response能拿到 handler、ModelAndView
依赖 Spring 容器不依赖依赖
执行顺序先执行后执行
数量多个多个

简单的请求过滤用 Filter,跟 Spring MVC 相关的用 Interceptor。 登录校验两种都可以,看习惯。


第 5 章:数据访问技术选型与实战 ​

数据访问是后端开发的核心,技术方案也很多。

5.1 数据访问技术全景 ​

Java 生态里数据访问技术很多,我们来梳理一下:

技术类型特点适用场景
JDBC底层最原始,最灵活,代码多极致性能、特殊需求
JdbcTemplate轻量封装Spring 封装的 JDBC,比原生好用简单项目、SQL 少
MyBatis半 ORMSQL 灵活,容易上手大多数业务系统
MyBatis-PlusMyBatis 增强单表 CRUD 不用写 SQL快速开发、单表多
JPA / Hibernate全 ORM不用写 SQL,面向对象简单 CRUD、快速原型
Spring Data JPAJPA 增强方法名查询、更方便同上
jOOQ类型安全 SQL用 Java 写 SQL,类型安全追求类型安全
QueryDSL类型安全查询跟 JPA/MyBatis 配合动态查询

怎么选?

  • 中小项目、快速开发:MyBatis-Plus(单表多,SQL 简单)
  • 复杂业务、SQL 多:MyBatis(SQL 灵活可控)
  • 简单 CRUD、原型开发:Spring Data JPA(开发快)
  • 极致性能、特殊需求:JDBC / JdbcTemplate
  • 类型安全、编译期检查:jOOQ / QueryDSL

目前国内最主流的是 MyBatis + MyBatis-Plus 组合。 国外 JPA 用的多一些。 没有最好的,只有最合适的,根据项目情况选。

5.2 MyBatis-Plus 实战(重点) ​

MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,单表 CRUD 不用写 SQL,非常方便。

核心特性:

  • 单表 CRUD 零 SQL
  • 条件构造器(Wrapper)
  • 分页插件
  • 代码生成器
  • 自动填充
  • 逻辑删除
  • 乐观锁
  • 多租户
  • ...

快速入门:

  1. 加依赖:
xml
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.5</version>
</dependency>
  1. 实体类:
java
@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  1. Mapper:
java
public interface UserMapper extends BaseMapper<User> {
}
  1. Service:
java
public interface UserService extends IService<User> {
}

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> 
        implements UserService {
}

就这么简单!单表 CRUD 都有了。

常用方法:

java
// 新增
userMapper.insert(user);

// 根据 ID 查询
User user = userMapper.selectById(id);

// 查询列表
List<User> list = userMapper.selectList(null);

// 条件查询
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getName, "张三")
       .gt(User::getAge, 18)
       .orderByDesc(User::getCreateTime);
List<User> list = userMapper.selectList(wrapper);

// 分页
Page<User> page = new Page<>(1, 10);
userMapper.selectPage(page, wrapper);

// 更新
userMapper.updateById(user);

// 删除
userMapper.deleteById(id);

MyBatis-Plus 是提升开发效率的神器。 单表操作基本不用写 SQL,复杂查询再写 XML。 国内现在新项目基本都用 MP。

5.3 数据库连接池对比 ​

连接池是数据库访问的必备组件。

连接池特点性能推荐
HikariCPSpring Boot 默认,轻量,高性能最高首选
Druid阿里开源,功能丰富,监控强高需要监控、SQL 防火墙用
Tomcat JDBCTomcat 自带中用 Tomcat 连接池时
C3P0老牌,历史悠久低不推荐,太老了
DBCPApache 出品低不推荐

HikariCP vs Druid:

维度HikariCPDruid
性能更高高
功能少而精丰富(监控、SQL 防火墙、加密等)
配置简单稍复杂
社区Spring Boot 默认,活跃国内活跃
推荐场景追求性能、简单够用需要监控、SQL 审计

一般项目用默认的 HikariCP 就行,性能最好。 如果需要 SQL 监控、慢查询分析、SQL 防火墙等功能,用 Druid。

5.4 Redis 实战 ​

Redis 是现在后端开发的必备技能,用途太广了。

Redis 能做什么:

  • 缓存(最常用)
  • 分布式锁
  • 计数器
  • 排行榜
  • 消息队列(简单场景)
  • 限流
  • 会话存储
  • 发布订阅
  • 地理位置
  • 布隆过滤器
  • ...

五种基本数据结构:

类型特点应用场景
String字符串,最基础缓存、计数器、分布式锁
Hash键值对集合对象缓存、购物车
List列表,有序可重复消息队列、最新列表
Set集合,无序不重复去重、交集并集差集、标签
ZSet有序集合,不重复排行榜、延时队列

Spring Boot 整合 Redis:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yaml
spring:
  data:
    redis:
      host: localhost
      port: 6379
      database: 0
      timeout: 3000ms
      lettuce:
        pool:
          max-active: 8
          max-idle: 8
          min-idle: 0

RedisTemplate 配置(JSON 序列化):

java
@Configuration
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(
            RedisConnectionFactory factory) {
        
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        
        // JSON 序列化器
        Jackson2JsonRedisSerializer<Object> jsonSerializer = 
            new Jackson2JsonRedisSerializer<>(Object.class);
        
        // key 用字符串序列化
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        
        // value 用 JSON 序列化
        template.setValueSerializer(jsonSerializer);
        template.setHashValueSerializer(jsonSerializer);
        
        template.afterPropertiesSet();
        return template;
    }
}

Redis 内容很多,这里只是入门。 缓存三大问题(穿透、击穿、雪崩)、分布式锁、持久化、集群... 都要深入学。

5.5 缓存三大问题 ​

缓存用不好会有很多问题,经典的三大问题:

1. 缓存穿透

问题:查询一个不存在的数据,缓存没命中,每次都查数据库。 如果有人恶意用不存在的 key 疯狂请求,数据库压力会很大。

解决方案:

  • 缓存空值:查不到也缓存,值为 null,设个短过期时间
  • 布隆过滤器:把所有存在的 key 放到布隆过滤器,请求先过布隆过滤器

2. 缓存击穿

问题:某个热点 key 过期了,瞬间大量请求过来,都打到数据库。 就像大坝决堤一样。

解决方案:

  • 互斥锁:缓存失效时,只有一个请求去查数据库并更新缓存,其他等待
  • 永不过期:热点 key 不设过期时间,后台异步更新

3. 缓存雪崩

问题:大量 key 同时过期,或者 Redis 挂了,所有请求都打到数据库。 比击穿更严重,是大面积的。

解决方案:

  • 过期时间加随机值:避免大量 key 同时过期
  • 多级缓存:本地缓存 + Redis 缓存
  • 高可用:Redis 集群、哨兵,避免单点故障
  • 限流降级:缓存挂了,限制数据库请求量,保证不挂

缓存三大问题是面试高频考点,也是实际项目中一定会遇到的。 一定要理解原理和解决方案。

5.6 缓存与数据库一致性 ​

缓存和数据库怎么保证一致性?这是个经典问题。

常见方案:

方案一:Cache Aside Pattern(最常用)

  • 读:先读缓存,有就返回,没有就读数据库,然后写缓存
  • 写:先更新数据库,再删除缓存

为什么是删除缓存,不是更新缓存?

  • 更新缓存可能会更新很多次,但很多可能根本没被读,浪费
  • 删除缓存更简单,下次读的时候再加载
  • 并发场景下更新缓存容易出问题

方案二:延时双删

  • 先删缓存
  • 再更新数据库
  • 延时一会再删缓存(防止并发读导致缓存旧数据)

方案三:订阅 binlog(Canal)

  • 更新数据库
  • 监听 binlog,异步更新缓存
  • 一致性更好,但复杂度高

最终一致性 vs 强一致性:

  • 大多数场景接受最终一致性,用 Cache Aside 就行
  • 要求强一致性的场景,直接读数据库,不用缓存

没有完美的方案,都是在一致性和性能之间做权衡。 大多数业务场景,Cache Aside + 删除缓存 就够用了。


第 6 章:配置体系详解 ​

6.1 配置文件格式 ​

Spring Boot 支持多种配置文件格式:

格式后缀特点推荐
Properties.properties传统,层级用点,简单简单配置
YAML.yml / .yaml层级清晰,支持列表,更简洁推荐
JSON.json不常用一般不用

YAML vs Properties:

yaml
# YAML
server:
  port: 8080
  servlet:
    context-path: /demo

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root
properties
# Properties
server.port=8080
server.servlet.context-path=/demo

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=root

YAML 更清晰,尤其是层级深的时候。 但 YAML 对缩进要求严格,注意不要用 Tab,要用空格。

6.2 配置优先级 ​

Spring Boot 的配置有很多来源,优先级从高到低:

  1. 命令行参数(--server.port=8080)
  2. 系统环境变量
  3. 操作系统环境变量
  4. application-{profile}.yml(jar 包外)
  5. application-{profile}.yml(jar 包内)
  6. application.yml(jar 包外)
  7. application.yml(jar 包内)
  8. @PropertySource 注解
  9. 默认值

优先级高的会覆盖优先级低的。 这个设计很灵活,打包后不用重新打包,改外部配置就行。

6.3 配置绑定的三种方式 ​

方式一:@Value

最简单,单个属性注入。

java
@RestController
public class TestController {
    
    @Value("${server.port}")
    private int port;
    
    @Value("${app.name:default}")  // 有默认值
    private String appName;
}

方式二:Environment

通过 Environment 对象获取。

java
@Autowired
private Environment env;

public void test() {
    String port = env.getProperty("server.port");
    String name = env.getProperty("app.name", "default");
}

方式三:@ConfigurationProperties(推荐)

批量绑定,类型安全。

java
@Data
@Component
@ConfigurationProperties(prefix = "app")
public class AppProperties {
    private String name = "default";
    private String version = "1.0";
    private boolean enable = true;
    private List<String> hosts;
    private Map<String, String> config;
}
yaml
app:
  name: myapp
  version: 2.0
  enable: true
  hosts:
    - host1
    - host2
  config:
    key1: value1
    key2: value2

三种方式对比:

维度@ValueEnvironment@ConfigurationProperties
适用场景单个属性动态获取批量属性绑定
类型安全一般弱强
松散绑定不支持不支持支持
复杂类型不支持不支持支持(List、Map、对象)
JSR-303 校验不支持不支持支持
推荐度⭐⭐⭐⭐⭐⭐⭐⭐⭐

批量配置用 @ConfigurationProperties,零散的用 @Value。 企业项目一般都用 @ConfigurationProperties,更规范。

6.4 多环境配置 ​

项目一般有多个环境:开发、测试、生产。

多 Profile 配置:

application.yml          # 公共配置
application-dev.yml      # 开发环境
application-test.yml     # 测试环境
application-prod.yml     # 生产环境

激活方式:

yaml
# application.yml
spring:
  profiles:
    active: dev  # 激活 dev 环境

或者命令行:

bash
java -jar app.jar --spring.profiles.active=prod

或者环境变量:

bash
SPRING_PROFILES_ACTIVE=prod java -jar app.jar

多环境配置是项目必备的。 不同环境的配置分开,代码一套,配置多套。

6.5 配置中心 ​

微服务架构下,服务多了,配置文件分散在各个服务里,不好管理。

这时候需要配置中心:统一管理配置,动态刷新。

常见配置中心:

配置中心来源特点推荐
Nacos阿里功能全,注册中心+配置中心,国内主流国内项目首选
Apollo携程功能强大,治理完善,灰度发布大公司、复杂需求
Spring Cloud ConfigSpring 官方配合 Git,轻量Spring Cloud 技术栈
ConsulHashiCorp服务发现+配置,Go 写的Go 技术栈

国内现在 Nacos 用的最多,既可以做注册中心,又可以做配置中心,一站式。 单体项目一般不用配置中心,多服务了再考虑。


第 7 章:安全框架对比与实战 ​

7.1 安全框架对比 ​

Java 生态主流的安全框架:

框架特点优势劣势适用场景
Spring SecuritySpring 家族,功能强大功能全,Spring 生态好,社区活跃学习曲线陡,配置复杂Spring 技术栈、复杂权限
Apache Shiro轻量,简单简单易用,不依赖 Spring,灵活功能不如 Security 全,更新慢简单项目、快速开发
Sa-Token国产,轻量极其简单,API 友好,功能全生态不如前两个国内项目、快速开发
JWT不是框架,是规范无状态,适合前后端分离无法主动失效,续签麻烦前后端分离、微服务

怎么选?

  • 项目简单、快速开发:Sa-Token / Shiro
  • Spring 技术栈、权限复杂:Spring Security
  • 前后端分离、无状态:JWT(配合上面任一框架)

以前 Spring Security 配置很复杂,现在 Spring Boot 整合后简单多了。 Sa-Token 是国产的,设计理念很现代,用起来非常顺手,推荐试试。

7.2 Spring Security 核心概念 ​

Spring Security 虽然复杂,但核心概念就几个:

核心组件:

组件作用
Authentication认证信息(用户、密码、权限)
SecurityContext安全上下文,存 Authentication
UserDetailsService加载用户信息
PasswordEncoder密码加密
Filter Chain过滤器链,认证授权都在这
AuthenticationManager认证管理器
AccessDecisionManager授权决策管理器

认证流程:

请求 → 过滤器链 → UsernamePasswordAuthenticationFilter
→ AuthenticationManager 认证
→ 认证成功 → 存 SecurityContext → 继续执行
→ 认证失败 → 跳登录页 / 返回错误

授权流程:

请求 → FilterSecurityInterceptor
→ 获取用户权限和资源所需权限
→ AccessDecisionManager 投票决策
→ 有权限 → 放行
→ 没权限 → 抛异常 → 403

Spring Security 的核心就是一堆过滤器。 理解了过滤器链,就理解了一半。

7.3 JWT 实战 ​

前后端分离项目,JWT 是现在的主流方案。

什么是 JWT:

  • JSON Web Token
  • 由三部分组成:Header.Payload.Signature
  • 服务端不用存,客户端存,无状态

JWT 工作流程:

1. 用户登录 → 验证成功 → 生成 JWT → 返回给前端
2. 前端把 JWT 存起来(localStorage / cookie)
3. 后续请求 header 里带上 JWT
4. 后端验证 JWT → 有效就放行

Spring Boot 整合 JWT:

java
// JWT 工具类
public class JwtUtil {
    private static final String SECRET = "your-secret-key";
    private static final long EXPIRE = 7 * 24 * 3600 * 1000;  // 7 天
    
    // 生成 token
    public static String generateToken(Long userId, String username) {
        return Jwts.builder()
                .setSubject(userId.toString())
                .claim("username", username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
    }
    
    // 解析 token
    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET)
                .parseClaimsJws(token)
                .getBody();
    }
}

JWT 的问题:

  • 无法主动失效(用户改密码了,旧 token 还能用)
  • 续签麻烦(快过期了怎么续)
  • token 泄露了怎么办

解决方案:

  • 黑名单:失效的 token 存 Redis,校验时查
  • 短有效期 + refresh token:access token 有效期短,用 refresh token 换新的
  • 存 Redis:还是服务端存,那就不是无状态了,但可控

JWT 不是银弹,有它的适用场景。 简单的、对安全性要求不高的场景,用 JWT 很方便。 要求高的,还是用 Session + Redis,或者配合黑名单。


第 8 章:缓存技术深度对比 ​

8.1 缓存技术全景 ​

缓存是提升性能的第一利器。

缓存的层次:

浏览器缓存 → CDN → 反向代理缓存 → 应用本地缓存 → 分布式缓存 → 数据库

越靠前,速度越快,容量越小。

Java 常用缓存技术:

类型技术特点适用场景
本地缓存HashMap / ConcurrentHashMap最简单极简单场景
Guava CacheGoogle 出品,功能丰富本地缓存首选
Caffeine高性能,Java 8+,Spring Boot 默认推荐,性能最好
Ehcache老牌,功能全传统项目
分布式缓存Redis最主流,功能丰富绝大多数场景
Memcached简单,纯内存简单缓存
Hazelcast分布式,支持 SQL分布式计算

8.2 本地缓存对比 ​

Caffeine vs Guava Cache vs Ehcache:

维度CaffeineGuava CacheEhcache
性能最高高中
功能丰富丰富很丰富
持久化不支持不支持支持
分布式不支持不支持支持(Terracotta)
Spring 集成支持(Spring Boot 2.x+ 默认)支持支持
学习成本低低中
推荐度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

Caffeine 是目前 Java 本地缓存的性能王者,Spring Boot 2.x+ 默认就是它。 新项目优先选 Caffeine。

8.3 Spring Cache 抽象 ​

Spring Cache 是 Spring 的缓存抽象,统一了各种缓存的使用方式。

常用注解:

注解作用
@EnableCaching开启缓存
@Cacheable查询缓存,有就返回,没有就执行方法并缓存
@CachePut更新缓存(方法一定会执行)
@CacheEvict删除缓存
@CacheConfig类级别配置
@Caching组合多个缓存操作

使用示例:

java
@Service
@CacheConfig(cacheNames = "user")
public class UserService {
    
    @Cacheable(key = "#id")
    public User getUserById(Long id) {
        // 查数据库
        return userMapper.selectById(id);
    }
    
    @CachePut(key = "#user.id")
    public User updateUser(User user) {
        userMapper.updateById(user);
        return user;
    }
    
    @CacheEvict(key = "#id")
    public void deleteUser(Long id) {
        userMapper.deleteById(id);
    }
}

Spring Cache 的好处是:代码里不用写缓存逻辑,加注解就行。 切换缓存实现(Caffeine → Redis)也不用改代码,改配置就行。

8.4 多级缓存 ​

为了更高的性能,可以用多级缓存:

  • L1:本地缓存(Caffeine),速度最快,容量小
  • L2:分布式缓存(Redis),速度快,容量大
  • L3:数据库,最慢,容量最大

请求流程:

请求 → 本地缓存 → 有 → 返回
            ↓ 没有
       Redis 缓存 → 有 → 回填本地缓存 → 返回
                   ↓ 没有
              数据库 → 回填 Redis → 回填本地缓存 → 返回

多级缓存的问题:

  • 一致性:本地缓存怎么跟 Redis 保持一致?
  • 失效:数据更新了,怎么通知所有节点清本地缓存?

解决方案:

  • 短过期时间:本地缓存过期时间设短一点(比如 1 分钟)
  • 消息通知:数据更新了,发 MQ 通知所有节点清缓存
  • 主动失效:用 Redis 发布订阅,通知清缓存

多级缓存性能更好,但复杂度也更高。 不是所有项目都需要,根据性能需求来。


第 9 章:消息队列选型与实战 ​

9.1 消息队列能做什么 ​

消息队列(MQ)是分布式系统的重要组件。

三大核心作用:

作用说明例子
异步不用等,后台慢慢做注册后发邮件、发短信
解耦系统之间不直接依赖下单后通知库存、物流、积分
削峰高峰期请求先存起来,慢慢消费秒杀、抢票

其他作用:

  • 最终一致性
  • 广播
  • 流量控制
  • 日志收集
  • ...

9.2 主流消息队列对比 ​

维度RabbitMQRocketMQKafkaPulsar
开发语言ErlangJavaScala/JavaJava
性能万级十万级十万级~百万级百万级
延迟微秒级毫秒级毫秒级毫秒级
可靠性高很高很高很高
功能丰富度很丰富丰富少(专注流处理)丰富
消息顺序不保证支持支持(分区内)支持
定时消息支持(插件)支持(原生)不支持支持
事务消息不支持支持支持支持
死信队列支持支持支持支持
运维复杂度中中高高
生态丰富国内丰富很丰富(大数据)新兴
适用场景中小项目、功能需求多电商、金融、国内项目大数据、日志、流处理云原生、下一代

怎么选?

  • 中小项目、功能多:RabbitMQ
  • 电商、金融、国内:RocketMQ
  • 大数据、日志、流处理:Kafka
  • 云原生、新一代:Pulsar

国内现在互联网公司用 RocketMQ 和 Kafka 比较多。 业务系统用 RocketMQ,大数据用 Kafka。 RabbitMQ 适合中小项目,功能丰富,上手快。

9.3 消息可靠性 ​

消息队列怎么保证消息不丢?这是面试高频问题。

消息丢失的三个环节:

生产者 → Broker → 消费者

1. 生产者丢失

问题:生产者发消息,网络问题,Broker 没收到。

解决方案:

  • 确认机制(publisher confirm):发完等 Broker 确认
  • 重试机制:失败了重试
  • 本地消息表:消息存本地,定时重发,保证最终送达

2. Broker 丢失

问题:Broker 收到消息,还没持久化,挂了。

解决方案:

  • 持久化:消息持久化到磁盘
  • 集群:多副本,一个挂了还有其他的
  • 同步刷盘:消息刷盘了才确认

3. 消费者丢失

问题:消费者收到消息,还没处理,程序崩了。

解决方案:

  • 手动 ACK:处理完了才确认,没处理完不确认
  • 重试机制:处理失败重试
  • 死信队列:重试多次都失败,进死信队列,人工处理

消息可靠性是 MQ 的核心问题。 要保证消息不丢,三个环节都要做处理。 但可靠性越高,性能越低,根据业务需求权衡。

9.4 消息幂等性 ​

消息可能重复消费,怎么保证消费多次结果一样?

幂等性:同一个消息消费一次和消费多次,结果一样。

实现方案:

方案原理适用场景
唯一 ID + 去重表每个消息有唯一 ID,消费前查去重表通用
数据库唯一键利用数据库唯一约束插入操作
乐观锁版本号,更新时带版本更新操作
Redis set消息 ID 存 Redis set,消费前检查通用,性能好
业务状态判断根据业务状态判断是否处理过有状态的业务

幂等性是 MQ 的必考题,也是实际项目必须考虑的。 消息队列一般都有重试机制,重复消息是常态,必须做幂等。


第 10 章:任务调度方案对比 ​

10.1 任务调度方案全景 ​

定时任务、异步任务,项目里经常用到。

常见方案:

方案特点适用场景
Thread + sleep最简单测试用,生产不用
TimerJDK 自带简单任务,单线程
ScheduledExecutorServiceJDK 线程池版简单定时任务
Spring @ScheduledSpring 注解,简单单体应用,简单任务
Quartz功能强大,持久化,集群复杂调度、企业级
XXL-Job分布式任务调度,可视化分布式、微服务
ElasticJob当当开源,分布式分布式、弹性伸缩
PowerJob新一代,功能丰富新一代调度框架

10.2 方案对比 ​

维度Spring ScheduleQuartzXXL-JobElasticJobPowerJob
上手难度简单中等简单中等中等
功能基础强大强大强大很强大
可视化无无有(管理后台)有有
持久化无支持支持支持支持
集群不支持支持支持支持支持
动态管理不支持支持(代码)支持(页面)支持支持
任务依赖不支持不支持支持不支持支持
分片不支持不支持支持支持支持
失败重试不支持不支持支持支持支持
适用场景单体简单任务单体复杂任务分布式任务调度分布式弹性任务新一代调度

怎么选?

  • 单体应用、简单任务:Spring @Scheduled
  • 单体应用、复杂调度:Quartz
  • 分布式、微服务:XXL-Job / ElasticJob / PowerJob
  • 国内项目:XXL-Job 用的最多,文档全,社区活跃

分布式任务调度框架,国内 XXL-Job 是绝对主流。 界面友好,功能齐全,文档详细,非常推荐。

10.3 异步任务 vs 消息队列 ​

很多人搞不清:什么时候用异步任务,什么时候用消息队列?

维度异步任务(@Async)消息队列(MQ)
复杂度简单复杂
可靠性低(进程挂了就丢了)高(持久化)
解耦弱(同一个应用内)强(跨系统)
削峰不能能
重试不支持支持
死信没有有
监控弱强
适用场景同一个应用内的简单异步跨系统、需要可靠、需要削峰

简单判断:

  • 同一个应用里,简单的异步,用 @Async
  • 跨系统、需要可靠投递、需要削峰,用 MQ

不要为了用 MQ 而用 MQ,简单异步用 @Async 就够了。 但重要的业务、不能丢的任务,一定要用 MQ。


第 11 章:日志体系与最佳实践 ​

11.1 日志框架全景 ​

Java 日志框架很多,有点乱,梳理一下:

日志门面(抽象层):

  • SLF4J:最主流的日志门面
  • Commons Logging (JCL):Spring 用的,老了

日志实现:

  • Logback:SLF4J 原生实现,Spring Boot 默认
  • Log4j2:Apache 出品,性能好
  • Log4j:老牌,已停止更新
  • JUL (java.util.logging):JDK 自带,不好用

关系:

应用代码 → SLF4J(门面) → Logback / Log4j2 / Log4j(实现)

最佳实践:代码里用 SLF4J,实现用 Logback 或 Log4j2。 这样以后想换实现,不用改代码。

11.2 Spring Boot 默认日志 ​

Spring Boot 默认用的是:SLF4J + Logback

配置文件:logback-spring.xml

简单配置:

xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 文件输出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>  <!-- 保留 30 天 -->
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    
    <!-- 根日志级别 -->
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
    
    <!-- 特定包日志级别 -->
    <logger name="com.example" level="DEBUG"/>
    <logger name="org.springframework" level="INFO"/>
</configuration>

11.3 日志级别 ​

级别说明使用场景
TRACE最细粒度追踪代码执行路径,很少用
DEBUG调试信息开发调试用
INFO一般信息正常运行信息,默认级别
WARN警告可能有问题,但不影响运行
ERROR错误出问题了,需要处理
FATAL致命错误系统崩溃,基本不用

使用原则:

  • 开发环境:DEBUG 级别,看详细信息
  • 生产环境:INFO 级别,只看重要信息
  • 出问题了:临时调到 DEBUG,排查完改回去

11.4 日志最佳实践 ​

1. 用占位符,不要字符串拼接

java
// 好
log.info("用户登录成功,userId: {}", userId);

// 不好
log.info("用户登录成功,userId: " + userId);

占位符的好处:如果日志级别不够,不会执行拼接,性能好。

2. 关键路径打日志

  • 接口入口:打印请求参数
  • 接口出口:打印返回结果
  • 异常:打印异常堆栈
  • 关键业务节点:下单、支付、发货等

3. 日志要有用

  • 不要打一堆没用的日志
  • 日志里要有上下文(用户 ID、订单号等),方便排查
  • 异常日志要打堆栈,不要只打 message

4. 敏感信息脱敏

  • 手机号、身份证、密码、银行卡号等敏感信息要脱敏
  • 不要明文打在日志里

5. 异步日志

  • 高并发场景用异步日志,减少 IO 对业务的影响
  • Logback、Log4j2 都支持异步

6. 日志收集

  • 微服务架构下,日志分散在各个服务
  • 用 ELK(Elasticsearch + Logstash + Kibana)统一收集
  • 或者 Loki + Grafana

日志是排查问题的第一手段,非常重要。 日志打得好,排查问题事半功倍。 日志打得烂,出了问题一头雾水。


第 12 章:监控与可观测性 ​

12.1 可观测性三支柱 ​

现代系统可观测性有三大支柱:

支柱作用工具
Metrics(指标)数值型数据,看趋势、告警Prometheus + Grafana
Logging(日志)事件记录,排查问题ELK / Loki
Tracing(链路追踪)请求链路,看耗时、找瓶颈SkyWalking / Jaeger / Zipkin

三者关系:

  • Metrics 告诉你"哪里出问题了"
  • Logging 告诉你"出了什么问题"
  • Tracing 告诉你"问题在哪一步"

12.2 Spring Boot Actuator ​

Spring Boot 自带的监控工具:Actuator。

常用端点:

端点作用
/actuator/health健康检查
/actuator/info应用信息
/actuator/metrics指标
/actuator/env环境变量
/actuator/beansBean 列表
/actuator/mappings接口映射
/actuator/loggers日志级别
/actuator/heapdump堆转储

配置:

yaml
management:
  endpoints:
    web:
      exposure:
        include: "*"  # 暴露所有端点(生产环境不要这么干)
  endpoint:
    health:
      show-details: always  # 显示详细健康信息

Actuator 是 Spring Boot 自带的监控基础。 生产环境注意安全,不要暴露所有端点,要加权限控制。

12.3 Prometheus + Grafana ​

现在最主流的监控方案。

架构:

  • Prometheus:时序数据库,采集和存储指标
  • Grafana:可视化仪表盘,展示图表
  • Alertmanager:告警

Spring Boot 整合:

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
yaml
management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  metrics:
    tags:
      application: ${spring.application.name}

常用监控指标:

  • JVM:堆内存、GC、线程数
  • 系统:CPU、内存、磁盘
  • 应用:QPS、响应时间、错误率
  • 业务:订单量、用户数、支付成功率

Prometheus + Grafana 是现在监控的标配。 不管什么项目,监控一定要做。 没有监控的系统,就是裸奔。

12.4 链路追踪 ​

微服务架构下,一个请求经过很多服务,出了问题不知道在哪。

链路追踪就是用来追踪请求在各个服务中的流转。

主流方案:

工具来源特点推荐
SkyWalking国产(华为)功能全,无侵入,UI 友好国内首选
JaegerUber轻量,CNCF 项目云原生
ZipkinTwitter老牌,简单简单场景
Pinpoint韩国功能强,侵入性低功能全面

国内 SkyWalking 用的最多,国产的,文档全,UI 友好。 微服务项目一定要上链路追踪,排查问题太方便了。


第 13 章:测试体系 ​

13.1 测试金字塔 ​

测试的金字塔模型:

        /\
       /  \        E2E 测试(端到端)
      /    \
     /------\      集成测试
    /        \
   /----------\    单元测试
  /            \
  • 单元测试:最多,最快,测单个方法/类
  • 集成测试:中等,测模块间协作
  • E2E 测试:最少,最慢,测整个系统

13.2 单元测试 ​

单元测试是测试的基础。

技术栈:

  • JUnit 5:测试框架(Spring Boot 3.x 默认)
  • Mockito:Mock 框架,模拟依赖
  • AssertJ:断言库,流式断言

示例:

java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    
    @Mock
    private UserMapper userMapper;
    
    @InjectMocks
    private UserServiceImpl userService;
    
    @Test
    void testGetUserById() {
        // 准备数据
        User user = new User();
        user.setId(1L);
        user.setName("张三");
        when(userMapper.selectById(1L)).thenReturn(user);
        
        // 执行
        User result = userService.getUserById(1L);
        
        // 断言
        assertThat(result).isNotNull();
        assertThat(result.getName()).isEqualTo("张三");
        verify(userMapper).selectById(1L);
    }
}

13.3 Spring Boot 集成测试 ​

Spring Boot 提供了 @SpringBootTest 注解,可以启动整个 Spring 容器来测试。

示例:

java
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    void testGetUser() throws Exception {
        mockMvc.perform(get("/users/1"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(200))
                .andExpect(jsonPath("$.data.name").value("张三"));
    }
}

测试切片:

不需要启动整个容器,只启动需要的部分:

注解作用
@WebMvcTest只测 Web 层
@DataJpaTest只测 JPA 层
@JsonTest只测 JSON 序列化

单元测试要快,不要依赖外部资源。 依赖数据库、Redis 的,用 H2 内存数据库或者 Mock。 测试要独立,不能互相依赖。

13.4 测试最佳实践 ​

  1. 测试命名清晰:方法名说明测什么、预期结果
  2. Given-When-Then 模式:准备 → 执行 → 断言
  3. 一个测试一个断言:每个测试只测一个点
  4. 测试要独立:测试之间不能有依赖
  5. 测试要快:单元测试秒级完成
  6. 覆盖率不是目标:不要为了覆盖率写无用的测试
  7. 边界值要测:null、空、最大值、异常情况

测试是质量的保障,也是重构的信心来源。 有完善的测试,改代码心里有底。 没有测试,改代码跟拆炸弹一样。


第 14 章:部署与运维 ​

14.1 打包方式 ​

JAR 包(推荐):

  • 内嵌容器,直接 java -jar 运行
  • 部署简单,一个文件搞定
  • Spring Boot 默认方式

WAR 包:

  • 需要外部 Tomcat
  • 老项目、需要统一部署的时候用

JAR vs WAR:

维度JARWAR
部署方式java -jar放到外部 Tomcat
容器内嵌外部
复杂度低高
灵活性高(每个应用独立容器)低(共享容器)
推荐✅老项目用

新项目一律用 JAR 包,简单方便。 WAR 包是历史遗留了。

14.2 运行参数 ​

常用启动参数:

bash
# 基本运行
java -jar app.jar

# 指定端口
java -jar app.jar --server.port=8080

# 指定环境
java -jar app.jar --spring.profiles.active=prod

# JVM 参数
java -Xms512m -Xmx1024m -XX:+UseG1GC -jar app.jar

# 远程调试
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -jar app.jar

常用 JVM 参数:

参数作用
-Xms初始堆内存
-Xmx最大堆内存
-Xmn新生代大小
-XX:+UseG1GC使用 G1 垃圾收集器
-XX:+HeapDumpOnOutOfMemoryErrorOOM 时自动 dump 堆
-XX:HeapDumpPathdump 文件路径
-XX:+PrintGCDetails打印 GC 详情

14.3 Docker 部署 ​

现在最流行的部署方式。

Dockerfile:

dockerfile
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

COPY target/app.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

构建镜像:

bash
docker build -t myapp:1.0 .

运行容器:

bash
docker run -d -p 8080:8080 --name myapp myapp:1.0

docker-compose:

yaml
version: '3'
services:
  app:
    image: myapp:1.0
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
    depends_on:
      - mysql
      - redis
      
  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=root
      
  redis:
    image: redis:7

Docker 部署是现在的标配。 环境一致,部署方便,迁移容易。

14.4 K8s 部署 ​

大规模微服务用 Kubernetes(K8s)。

Deployment + Service:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 500m
            memory: 512Mi
          limits:
            cpu: 1000m
            memory: 1Gi
        livenessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
        readinessProbe:
          httpGet:
            path: /actuator/health
            port: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP

K8s 是容器编排的事实标准。 微服务、大规模部署一定要学 K8s。 小项目 Docker + docker-compose 就够了。


第 15 章:前沿技术与未来趋势 ​

15.1 Spring Boot 3.x 新特性 ​

Spring Boot 3.0 是一个大版本,变化很大。

核心变化:

变化说明
JDK 17+最低要求 JDK 17
Jakarta EE 9+javax.* → jakarta.* 命名空间
Spring Framework 6基于 Spring 6
GraalVM 原生镜像官方支持 AOT 编译
虚拟线程预览配合 JDK 21 的虚拟线程
Observability增强可观测性
移除老东西移除了很多过时的支持

从 2.x 升级到 3.x 注意事项:

  1. JDK 要升到 17+
  2. 所有 javax.* 改成 jakarta.*
  3. 第三方依赖要确认支持 3.x
  4. 移除的功能要找替代

Spring Boot 3.x 是未来的方向,新项目建议直接上 3.x。 老项目如果稳定,不着急升,等生态成熟了再说。

15.2 GraalVM 与原生镜像 ​

什么是 GraalVM:

  • Oracle 开发的高性能虚拟机
  • 支持 AOT(Ahead-Of-Time)编译
  • 可以把 Java 程序编译成原生可执行文件

原生镜像的好处:

  • 启动极快(毫秒级)
  • 内存占用极低
  • 不需要 JVM

缺点:

  • 编译慢
  • 动态特性受限(反射、动态代理等需要配置)
  • 调试困难

Spring Boot 3.x 支持:

bash
# 构建原生镜像
mvn native:compile

# 或者用 Buildpacks
mvn spring-boot:build-image -Pnative

原生镜像特别适合 Serverless、CLI 工具、函数计算等场景。 启动快、内存小,按需启动,用完就销毁。 传统 Web 应用暂时不建议,生态还在完善中。

15.3 虚拟线程(Project Loom) ​

JDK 21 正式引入了虚拟线程(Virtual Thread)。

什么是虚拟线程:

  • 轻量级线程,由 JVM 管理,不是 OS 线程
  • 一个 OS 线程可以跑很多虚拟线程
  • 创建成本极低,可以开几十上百万个
  • 阻塞是免费的(阻塞虚拟线程不会阻塞 OS 线程)

对 Spring Boot 的影响:

  • 以前 Tomcat 线程池最多几百个线程
  • 现在可以开几万、几十万个虚拟线程
  • 吞吐量大幅提升
  • 不用再写异步代码了,同步代码就能有异步的性能

Spring Boot 开启虚拟线程:

yaml
spring:
  threads:
    virtual:
      enabled: true

虚拟线程是 Java 的革命性特性。 可能会改变 Java 后端的编程模型,不用再搞各种异步了。 但还比较新,需要时间验证,生产环境谨慎使用。

15.4 响应式编程 ​

响应式编程(Reactive)是另一种编程范式。

Spring WebFlux:

  • Spring 的响应式 Web 框架
  • 基于 Reactor
  • 非阻塞,高并发
  • 跟 Spring MVC 并列

响应式 vs 传统 MVC:

维度Spring MVCSpring WebFlux
编程模型命令式响应式
阻塞阻塞非阻塞
并发模型线程池事件循环
学习曲线平缓陡峭
适用场景大多数业务高并发、流处理
生态成熟还在发展

响应式编程性能更好,但学习成本高,调试困难。 大多数业务场景用 MVC 就够了。 高并发、IO 密集型的场景可以考虑 WebFlux。

15.5 其他前沿方向 ​

  • Serverless:函数即服务,按需付费
  • Service Mesh:服务网格(Istio、Linkerd)
  • eBPF:内核级可观测性、网络
  • AI 集成:Spring AI,大模型集成
  • 低代码 / 无代码:快速开发平台
  • WebAssembly:跨语言、高性能

技术发展很快,要保持学习。 但也不用什么火就学什么,先把基础打牢,再根据兴趣和工作需要深入。


第 16 章:性能优化实战 ​

16.1 性能优化方法论 ​

优化原则:

  1. 不要过早优化:先让它跑起来,再优化
  2. 先测量再优化:用数据说话,不要猜
  3. 找瓶颈:80% 的性能问题在 20% 的地方
  4. 权衡取舍:性能、复杂度、成本之间找平衡

优化步骤:

发现问题 → 定位瓶颈 → 分析原因 → 优化 → 验证 → 持续监控

16.2 常见性能瓶颈 ​

层级常见瓶颈优化手段
前端资源大、请求多压缩、缓存、CDN、懒加载
网关并发不够扩容、调优
应用代码慢、锁竞争、GC代码优化、缓存、异步
缓存穿透、击穿、雪崩见第 5 章
数据库慢 SQL、锁、索引索引优化、SQL 优化、分库分表
网络延迟高、带宽不够就近接入、扩容

16.3 应用层优化 ​

1. 加缓存

  • 热点数据加缓存
  • 本地缓存 + 分布式缓存多级缓存

2. 异步化

  • 耗时操作异步处理
  • 用 MQ 解耦和削峰

3. 池化技术

  • 线程池、连接池、对象池
  • 合理设置池大小

4. 代码优化

  • 避免在循环里查数据库
  • 批量操作代替单次操作
  • 减少对象创建
  • 用合适的数据结构

5. JVM 调优

  • 堆大小设置
  • 垃圾收集器选择
  • GC 调优

16.4 数据库优化 ​

数据库是最常见的瓶颈。

1. 索引优化

  • 经常查询的字段加索引
  • 联合索引注意顺序
  • 避免索引失效
  • 不要建太多索引(影响写入)

2. SQL 优化

  • 避免 select *
  • 避免大事务
  • 分页优化(深分页)
  • 用 explain 分析执行计划

3. 读写分离

  • 主库写,从库读
  • 一主多从,提升读性能

4. 分库分表

  • 数据量大了,单表扛不住
  • 水平分表、垂直分库
  • 用 ShardingSphere 等中间件

数据库优化是个大话题,够写一本书了。 记住:先优化索引和 SQL,不行再读写分离,最后才考虑分库分表。 分库分表复杂度很高,不要上来就搞。

16.5 性能监控工具 ​

工具作用
JProfiler / ArthasJVM 性能分析
JMeter / wrk压测
Prometheus + Grafana监控指标
SkyWalking链路追踪,找慢接口
ExplainSQL 执行计划分析
Flame Graph火焰图,看 CPU 热点

性能优化的第一步是测量。 用工具找到瓶颈,再针对性优化。 不要凭感觉优化,很多时候你猜的瓶颈根本不是瓶颈。


第 17 章:架构设计与最佳实践 ​

17.1 项目结构最佳实践 ​

标准分层结构:

com.example.project
├── ProjectApplication.java          # 启动类
├── common/                          # 公共模块
│   ├── result/                      # 统一返回结果
│   ├── exception/                   # 异常定义
│   ├── constant/                    # 常量
│   └── utils/                       # 工具类
├── config/                          # 配置类
│   ├── WebConfig.java
│   ├── RedisConfig.java
│   └── MybatisPlusConfig.java
├── controller/                      # 控制层
│   ├── UserController.java
│   └── OrderController.java
├── service/                         # 业务层
│   ├── UserService.java
│   ├── impl/
│   │   └── UserServiceImpl.java
│   └── ...
├── mapper/                          # 数据访问层
│   ├── UserMapper.java
│   └── ...
├── entity/                          # 数据库实体
│   ├── User.java
│   └── ...
├── dto/                             # 数据传输对象
│   ├── req/                         # 请求 DTO
│   └── resp/                        # 响应 DTO
├── vo/                              # 视图对象
├── convert/                         # 对象转换器
├── interceptor/                     # 拦截器
├── filter/                          # 过滤器
└── aspect/                          # 切面

分层原则:

  • 上层依赖下层,不能反向依赖
  • 每层职责单一
  • 跨层调用通过接口

项目结构没有标准答案,但要清晰、一致。 团队约定好,大家都遵守,代码就好维护。

17.2 常用设计模式 ​

Spring 里到处都是设计模式,了解设计模式能帮你更好地理解 Spring。

Spring 中常用的设计模式:

模式应用场景
工厂模式BeanFactory、ApplicationContext
单例模式Spring Bean 默认单例
代理模式AOP、事务
模板方法模式JdbcTemplate、RestTemplate
观察者模式事件机制、ApplicationEvent
策略模式HandlerMapping、HandlerAdapter
装饰器模式BeanWrapper
责任链模式过滤器链、拦截器链

设计模式是前人总结的经验。 不用为了用模式而用模式,合适的场景用合适的模式。 看懂 Spring 源码里的设计模式,对你自己写代码也很有帮助。

17.3 代码规范 ​

为什么要有规范:

  • 统一风格,可读性好
  • 减少低级错误
  • 降低维护成本
  • 新人上手快

规范包括:

  • 命名规范(类名、方法名、变量名)
  • 代码格式(缩进、空行、括号)
  • 注释规范
  • 异常处理规范
  • 日志规范
  • 提交规范

工具:

  • Checkstyle:代码风格检查
  • SpotBugs / FindBugs:Bug 检查
  • PMD:代码质量检查
  • Alibaba Java Coding Guidelines:阿里 Java 开发规约插件

规范很重要,尤其是团队开发。 代码是写给人看的,顺便给机器执行。 写代码的时候想想:别人能不能看懂?三个月后自己能不能看懂?

17.4 安全最佳实践 ​

OWASP Top 10(最常见的安全风险):

  1. 注入(SQL 注入、命令注入)
  2. 失效的身份认证
  3. 敏感数据泄露
  4. XML 外部实体(XXE)
  5. 失效的访问控制
  6. 安全配置错误
  7. 跨站脚本(XSS)
  8. 不安全的反序列化
  9. 使用含有已知漏洞的组件
  10. 不足的日志和监控

后端安全清单:

  • [ ] 密码加密存储(BCrypt)
  • [ ] SQL 注入防护(参数化查询)
  • [ ] XSS 防护(输出转义)
  • [ ] CSRF 防护
  • [ ] 越权检查(水平越权、垂直越权)
  • [ ] 敏感数据脱敏
  • [ ] 接口限流
  • [ ] 输入校验
  • [ ] 依赖漏洞扫描
  • [ ] 日志审计

安全很重要,出了事就是大事。 不要觉得"我们是小公司,没人攻击我们"。 很多攻击是脚本自动扫的,不管你大小。

17.5 微服务架构演进 ​

架构演进路径:

单体应用 → 垂直拆分 → SOA → 微服务 → 服务网格

什么时候考虑微服务:

  • 团队大了,单体开发效率低
  • 系统复杂了,单体不好维护
  • 需要独立部署、独立扩展
  • 不同模块技术栈不一样

微服务不是银弹:

  • 复杂度大大增加
  • 分布式问题(一致性、容错、监控...)
  • 运维成本高
  • 调试困难

建议:

  • 小团队、小项目,单体就好
  • 随着业务发展,逐步拆分
  • 不要上来就微服务,很多项目根本不需要

架构是演化出来的,不是设计出来的。 合适的架构就是最好的架构。 不要为了微服务而微服务。


第 18 章:学习路线与资源推荐 ​

18.1 Spring Boot 学习路线 ​

第一阶段:入门

  • Java 基础
  • Spring 基础(IOC、AOP)
  • Spring Boot 快速入门
  • Web 开发
  • MyBatis / MyBatis-Plus
  • 做个小项目

第二阶段:进阶

  • 自动配置原理
  • 各种 starter 整合
  • 缓存、消息队列、安全
  • 性能优化
  • 监控和运维
  • 做个完整项目

第三阶段:深入

  • Spring 源码
  • Spring Boot 源码
  • 设计模式
  • 架构设计
  • 微服务
  • 中间件原理

第四阶段:专家

  • 深入 JVM
  • 操作系统、网络
  • 分布式系统
  • 技术选型和架构设计
  • 团队管理和技术规划

学习是个循序渐进的过程。 不要急于求成,一步一步来。 多动手,多实践,光看是学不会的。

18.2 推荐资源 ​

官方文档:

书籍:

  • 《Spring Boot 实战》
  • 《Spring 实战》
  • 《深入理解 Java 虚拟机》
  • 《设计模式之禅》
  • 《高性能 MySQL》
  • 《Redis 设计与实现》

网站:

视频:

  • B站搜"Spring Boot 教程",很多免费的
  • 黑马程序员、尚硅谷、动力节点等

社区:

18.3 给初学者的建议 ​

  1. 多动手:看十遍不如敲一遍,代码是敲出来的,不是看出来的。

  2. 多思考:不要只抄代码,要想为什么这么写,有没有更好的方式。

  3. 多调试:遇到问题先自己 Debug,一步步跟,比问别人印象深。

  4. 打好基础:Java 基础、数据结构、算法、计算机网络、操作系统,这些基础很重要。

  5. 不要贪多:技术学不完,先把一个方向学深,再扩展。

  6. 写博客:学了东西写下来,输出倒逼输入,也方便以后复习。

  7. 做项目:找个完整的项目做一遍,把学到的知识串起来。

  8. 看源码:有能力了看看 Spring 源码,收获会很大。

  9. 保持学习:技术发展很快,要持续学习。

  10. 不要焦虑:技术太多学不完很正常,根据自己的节奏来。

编程是个手艺活,靠的是积累。 没有捷径,就是多练、多想、多总结。 坚持下去,你会越来越强。


写在最后 ​

恭喜你看到了这里!

这篇教程涵盖了 Spring Boot 从入门到进阶的方方面面,从基础用法到核心原理,从技术选型到最佳实践,从传统开发到前沿趋势。

希望这篇教程能帮到你。

记住:

  • 技术是工具,解决问题才是目的
  • 没有最好的技术,只有最合适的
  • 保持好奇心,保持学习的热情
  • 实践出真知

路漫漫其修远兮,吾将上下而求索。

加油!


基于 Vite 强力驱动 | 纯静态轻量托管