跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring Boot 缓存机制与性能优化实践

Spring Boot 缓存机制与性能优化实践涵盖了从本地内存到 Redis 分布式缓存的完整集成方案。通过配置 Spring Cache 抽象层,开发者可以便捷地使用 @Cacheable 等注解屏蔽底层存储细节。文章演示了依赖引入、配置文件调整及业务逻辑改造的具体步骤,展示了如何通过缓存减少数据库访问压力,显著提升接口响应速度与系统吞吐量。

疯疯癫癫发布于 2026/3/28更新于 2026/10/2598 浏览
Spring Boot 缓存机制与性能优化实践

Spring Boot 缓存机制与性能优化实践

在 Java 开发中,缓存与性能优化是提升系统响应速度和吞吐量的关键手段。通过合理引入缓存层,我们可以有效减少数据库的访问压力,改善用户体验。本文将深入探讨 Spring Boot 如何集成本地缓存与 Redis 分布式缓存,并通过实际代码演示具体的落地步骤。

缓存与性能优化概述

缓存本质上是一种临时数据存储区,旨在加速数据访问。常见的缓存方案包括内存缓存(如 ConcurrentHashMap、Guava Cache)、分布式缓存(如 Redis、Memcached)以及浏览器缓存。性能优化则是一个更广泛的概念,涵盖缓存策略、数据库查询调优、代码逻辑重构及服务器资源配置等多个维度。

在实际场景中,选择合适的缓存方案至关重要。对于单机应用,本地缓存足以应对;而对于高并发或集群环境,Redis 等分布式缓存则是必选项。

集成 Spring Cache 本地缓存

Spring Boot 提供了统一的缓存抽象(Spring Cache),让我们可以专注于业务逻辑而非底层存储细节。以下是基于本地内存缓存的完整实现流程。

1. 依赖配置

首先需要在 pom.xml 中添加缓存启动器依赖:

<dependencies>
    <!-- Web 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 缓存核心依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2. 启用缓存功能

在主启动类上添加 @EnableCaching 注解,开启 Spring 的缓存支持:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

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

3. 实体与 Repository 层

为了模拟真实场景,我们定义一个产品实体和 Repository 接口。注意这里使用了 Thread.sleep 来模拟数据库查询延迟。

public class Product {
    private Long id;
    private String productId;
    private String productName;
    private double price;
    private int stock;

    // 构造函数、Getter/Setter 省略,请确保格式规范
    public Product() {}

    public Product(Long id, String productId, String productName, double price, int stock) {
        this.id = id;
        this.productId = productId;
        this.productName = productName;
        this.price = price;
        this.stock = stock;
    }

    // Getter and Setter methods...
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getProductId() { return productId; }
    public void setProductId(String productId) { this.productId = productId; }
    public String getProductName() { return productName; }
    public void setProductName(String productName) { this.productName = productName; }
    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
    public int getStock() { return stock; }
    public void setStock(int stock) { this.stock = stock; }

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", productId='" + productId + '\'' +
                ", productName='" + productName + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }
}
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;

@Repository
public class ProductRepository {
    private List<Product> products = new ArrayList<>();

    public ProductRepository() {
        products.add(new Product(1L, "P001", "手机", 1000.0, 100));
        products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
        products.add(new Product(3L, "P003", "电视", 3000.0, 80));
        products.add(new Product(4L, "P004", "手表", 500.0, 200));
        products.add(new Product(5L, "P005", "耳机", 300.0, 150));
    }

    public List<Product> getAllProducts() {
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
        return products;
    }

    public Product getProductById(Long id) {
        try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
        return products.stream().filter(p -> p.getId().equals(id)).findFirst().orElse(null);
    }

    public void addProduct(Product product) {
        product.setId((long) (products.size() + 1));
        products.add(product);
    }

    public void updateProduct(Product product) {
        Product existing = getProductById(product.getId());
        if (existing != null) {
            existing.setProductId(product.getProductId());
            existing.setProductName(product.getProductName());
            existing.setPrice(product.getPrice());
            existing.setStock(product.getStock());
        }
    }

    public void deleteProduct(Long id) {
        products.removeIf(p -> p.getId().equals(id));
    }
}

4. Service 层缓存注解

这是核心部分。我们使用 @Cacheable 标记需要缓存的方法,@CachePut 用于更新后刷新缓存,@CacheEvict 用于删除时清除缓存。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    // 缓存所有产品列表,key 为 "products"
    @Cacheable(value = "products")
    public List<Product> getAllProducts() {
        System.out.println("从数据库查询所有产品信息");
        return productRepository.getAllProducts();
    }

    // 缓存单个产品,key 为 "product:id"
    @Cacheable(value = "product", key = "#id")
    public Product getProductById(Long id) {
        System.out.println("从数据库查询产品信息:" + id);
        return productRepository.getProductById(id);
    }

    // 更新操作,先执行方法再写入缓存
    @CachePut(value = "product", key = "#product.id")
    public Product addProduct(Product product) {
        System.out.println("添加产品信息:" + product);
        productRepository.addProduct(product);
        return product;
    }

    @CachePut(value = "product", key = "#product.id")
    public Product updateProduct(Product product) {
        System.out.println("更新产品信息:" + product);
        productRepository.updateProduct(product);
        return product;
    }

    // 删除操作,清除对应缓存
    @CacheEvict(value = "product", key = "#id")
    public void deleteProduct(Long id) {
        System.out.println("删除产品信息:" + id);
        productRepository.deleteProduct(id);
    }
}

5. Controller 层与应用测试

Controller 层保持标准 RESTful 风格,无需修改缓存逻辑。启动应用后,观察控制台输出即可验证缓存效果:第一次请求会打印'从数据库查询',第二次请求则直接返回结果,不再打印日志,说明命中了缓存。

集成 Redis 分布式缓存

当应用部署在多台服务器上时,本地缓存无法共享数据,此时需要切换到 Redis。主要区别在于依赖引入和配置文件调整。

1. 依赖与配置

在 pom.xml 中增加 Redis 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

在 application.properties 中配置 Redis 连接信息:

server.port=8080
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0

2. 业务逻辑复用

Service 层的代码与本地缓存版本完全一致。Spring Cache 默认会根据配置自动切换后端存储。只要启用了 Redis 客户端并配置正确,@Cacheable 等注解会自动将数据序列化存入 Redis。

3. 测试验证

运行测试类,对比两次请求的响应时间和控制台日志。你会发现,即使重启应用,Redis 中的数据依然存在,实现了真正的分布式缓存效果。

总结

通过本文的实践,我们掌握了 Spring Boot 缓存集成的核心流程。无论是简单的本地内存缓存还是生产级的 Redis 分布式缓存,Spring Cache 都提供了统一的编程模型。关键在于根据业务场景选择合适的缓存策略,合理使用注解控制缓存行为,从而在保证数据一致性的前提下,最大化系统的性能表现。

目录

  1. Spring Boot 缓存机制与性能优化实践
  2. 缓存与性能优化概述
  3. 集成 Spring Cache 本地缓存
  4. 1. 依赖配置
  5. 2. 启用缓存功能
  6. 3. 实体与 Repository 层
  7. 4. Service 层缓存注解
  8. 5. Controller 层与应用测试
  9. 集成 Redis 分布式缓存
  10. 1. 依赖与配置
  11. 2. 业务逻辑复用
  12. 3. 测试验证
  13. 总结

更多推荐文章

查看全部
  • Seedance 2.0 深度解析:AI 视频生成迈向工业级可控
  • 异步消息队列设计与 Rust 实战集成
  • 蓝桥杯算法实战指南:递推、递归、BFS 与 DFS 详解
  • 使用 Mac Mini 部署 OpenClaw 打造金融 AI 分析助手
  • Adobe Illustrator 2025 安装步骤与使用技巧指南
  • B 站:从二次元社区到 AI 创新孵化器的转变
  • Python 列表转 Excel 实战:一维、二维与字典格式
  • HTML 网页结构搭建:从语义化标签到整站规划
  • .NET 集成 GoView 低代码可视化大屏实战详解
  • Spring AI 重塑 Java 生态 AI 开发实践
  • 二分答案专题实战:木材加工与砍树问题详解
  • 绿联 NAS 配置 WebDAV 公网访问及 RaiDrive 挂载实战
  • 通达信主力建仓指标源码
  • Flutter Web 开发:解决跨域(CORS)问题的方法
  • 图论算法总结:单源最短路(Dijkstra 与 SPFA)
  • Dify 本地 Docker 部署教程
  • Vitis 实战:从零将 AI 模型部署到 FPGA
  • C++ 实现 LRU Cache 缓存淘汰算法
  • 渗透测试实战:SRC 漏洞挖掘与提交流程指南
  • 自然语言处理在客户服务领域的应用与实战

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online