Spring Boot 缓存与性能优化
学习目标与重点提示
学习目标:掌握 Spring Boot 缓存与性能优化的核心概念与使用方法,包括缓存的定义与特点、性能优化的定义与特点、Spring Boot 与缓存的集成、Spring Boot 的实际应用场景,学会在实际开发中处理缓存与性能优化问题。
重点:
- 缓存的定义与特点
- 性能优化的定义与特点
- Spring Boot 与缓存的集成
- Spring Boot 的实际应用场景
缓存与性能优化概述
缓存与性能优化是 Java 开发中的重要组件,用于提高应用程序的响应速度和吞吐量。
缓存的定义
定义:缓存是一种用于存储数据的临时存储区,用于提高数据的访问速度。
作用:
- 减少数据库的访问压力。
- 提高应用程序的响应速度。
- 提高应用程序的吞吐量。
常见的缓存:
- 内存缓存:包括 ConcurrentHashMap 和 Guava Cache。
- 分布式缓存:包括 Redis 和 Memcached。
- 浏览器缓存:包括 HTTP 缓存和浏览器本地存储。
结论:缓存是一种用于存储数据的临时存储区,作用是减少数据库的访问压力、提高应用程序的响应速度、提高应用程序的吞吐量。
性能优化的定义
定义:性能优化是指对应用程序进行优化,以提高其响应速度和吞吐量。
作用:
- 提高用户体验。
- 减少服务器的资源消耗。
- 提高系统的可靠性。
常见的性能优化方法:
- 缓存优化:使用缓存减少数据库的访问压力。
- 数据库优化:优化数据库的查询语句和索引。
- 代码优化:优化代码的结构和逻辑。
- 服务器优化:优化服务器的配置和资源分配。
结论:性能优化是指对应用程序进行优化,作用是提高用户体验、减少服务器的资源消耗、提高系统的可靠性。
Spring Boot 与缓存的集成
Spring Boot 与缓存的集成是 Java 开发中的重要内容。
集成 Spring Cache 的步骤
定义:集成 Spring Cache 的步骤是指使用 Spring Boot 与 Spring Cache 集成的方法。
步骤:
- 创建 Spring Boot 项目。
- 添加所需的依赖。
- 配置缓存。
- 创建业务层。
- 创建控制器类。
- 测试应用。
示例:
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>
application.properties 文件中的配置:
# 服务器端口
server.port=8080
实体类:
public class Product {
private Long id;
private String productId;
private String productName;
private double price;
private int stock;
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 和 Setter 方法
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 +
'}';
}
}
Repository 接口:
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@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() {
// 模拟数据库查询,延迟 1 秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return products;
}
public Product getProductById(Long id) {
// 模拟数据库查询,延迟 1 秒
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return products.stream().filter(product -> product.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 existingProduct = getProductById(product.getId());
if (existingProduct != null) {
existingProduct.setProductId(product.getProductId());
existingProduct.setProductName(product.getProductName());
existingProduct.setPrice(product.getPrice());
existingProduct.setStock(product.getStock());
}
}
public void deleteProduct(Long id) {
products.removeIf(product -> product.getId().equals(id));
}
}
Service 类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
@Cacheable(value = "products")
public List<Product> getAllProducts() {
System.out.println("从数据库查询所有产品信息");
return productRepository.getAllProducts();
}
@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);
}
}
控制器类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping("/")
public List<Product> getAllProducts() {
return productService.getAllProducts();
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return productService.getProductById(id);
}
@PostMapping("/add")
public Product addProduct(@RequestBody Product product) {
return productService.addProduct(product);
}
@PutMapping("/edit/{id}")
public Product editProduct(@PathVariable Long id, @RequestBody Product product) {
product.setId(id);
return productService.updateProduct(product);
}
@DeleteMapping("/delete/{id}")
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
}
应用启动类:
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);
}
}
测试类:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class CacheApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {}
@Test
void testGetAllProducts() {
// 第一次访问,从数据库查询
List<Product> products1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
assertThat(products1).hasSize(5);
// 第二次访问,从缓存获取
List<Product> products2 = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
assertThat(products2).hasSize(5);
}
@Test
void testGetProductById() {
// 第一次访问,从数据库查询
Product product1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product1).isNotNull();
// 第二次访问,从缓存获取
Product product2 = restTemplate.getForObject("http://localhost:" + port + "/api/products/1", Product.class);
assertThat(product2).isNotNull();
}
}
结论:集成 Spring Cache 的步骤包括创建 Spring Boot 项目、添加所需的依赖、配置缓存、创建业务层、创建控制器类、测试应用。
集成 Redis 缓存的步骤
定义:集成 Redis 缓存的步骤是指使用 Spring Boot 与 Redis 缓存集成的方法。
步骤:
- 创建 Spring Boot 项目。
- 添加所需的依赖。
- 配置 Redis。
- 创建业务层。
- 创建控制器类。
- 测试应用。
示例:
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>
<!-- Redis 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.properties 文件中的配置:
# 服务器端口
server.port=8080
# Redis 连接信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0
实体类、Repository 接口、Service 类、控制器类、应用启动类及测试类代码逻辑与上述 Spring Cache 集成类似,主要区别在于启动类名称及依赖配置。此处省略重复代码,重点在于 Redis 依赖的引入与配置。
结论:集成 Redis 缓存的步骤包括创建 Spring Boot 项目、添加所需的依赖、配置 Redis、创建业务层、创建控制器类、测试应用。
Spring Boot 的实际应用场景
在实际开发中,Spring Boot 缓存与性能优化的应用场景非常广泛,如:
- 实现产品信息的缓存优化。
- 实现用户信息的缓存优化。
- 实现订单信息的缓存优化。
- 实现支付信息的缓存优化。
示例: (参考上文 Service 类与 Controller 类代码)
输出结果:
- 第一次访问 http://localhost:8080/api/products/,控制台输出:从数据库查询所有产品信息,响应时间约 1 秒。
- 第二次访问 http://localhost:8080/api/products/,控制台无输出,响应时间约 0 毫秒。
结论:在实际开发中,Spring Boot 缓存与性能优化的应用场景非常广泛,需要根据实际问题选择合适的缓存和性能优化方法。
总结
本章我们学习了 Spring Boot 缓存与性能优化,包括缓存的定义与特点、性能优化的定义与特点、Spring Boot 与缓存的集成、Spring Boot 的实际应用场景,学会了在实际开发中处理缓存与性能优化问题。其中,缓存的定义与特点、性能优化的定义与特点、Spring Boot 与缓存的集成、Spring Boot 的实际应用场景是本章的重点内容。从下一章开始,我们将学习 Spring Boot 的其他组件、微服务等内容。


