31.1 学习目标与重点提示
学习目标:掌握Spring Boot缓存与性能优化的核心概念与使用方法,包括缓存的定义与特点、性能优化的定义与特点、Spring Boot与缓存的集成、Spring Boot的实际应用场景,学会在实际开发中处理缓存与性能优化问题。
重点:缓存的定义与特点、性能优化的定义与特点、Spring Boot与缓存的集成、Spring Boot的实际应用场景。
31.2 缓存与性能优化概述
缓存与性能优化是Java开发中的重要组件,用于提高应用程序的响应速度和吞吐量。
31.2.1 缓存的定义
定义:缓存是一种用于存储数据的临时存储区,用于提高数据的访问速度。
作用:
- 减少数据库的访问压力。
- 提高应用程序的响应速度。
- 提高应用程序的吞吐量。
常见的缓存:
- 内存缓存:包括ConcurrentHashMap和Guava Cache。
- 分布式缓存:包括Redis和Memcached。
- 浏览器缓存:包括HTTP缓存和浏览器本地存储。
✅ 结论:缓存是一种用于存储数据的临时存储区,作用是减少数据库的访问压力、提高应用程序的响应速度、提高应用程序的吞吐量。
31.2.2 性能优化的定义
定义:性能优化是指对应用程序进行优化,以提高其响应速度和吞吐量。
作用:
- 提高用户体验。
- 减少服务器的资源消耗。
- 提高系统的可靠性。
常见的性能优化方法:
- 缓存优化:使用缓存减少数据库的访问压力。
- 数据库优化:优化数据库的查询语句和索引。
- 代码优化:优化代码的结构和逻辑。
- 服务器优化:优化服务器的配置和资源分配。
✅ 结论:性能优化是指对应用程序进行优化,作用是提高用户体验、减少服务器的资源消耗、提高系统的可靠性。
31.3 Spring Boot与缓存的集成
Spring Boot与缓存的集成是Java开发中的重要内容。
31.3.1 集成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>
AI写代码xml
1234567891011121314151617181920
application.properties文件中的配置:
# 服务器端口
server.port=8080
AI写代码properties
12
实体类:
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 +
'}';
}
}
AI写代码java
运行
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
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));
}
}
AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
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);
}
}
AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445
控制器类:
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);
}
}
AI写代码java
运行
12345678910111213141516171819202122232425262728293031323334353637
应用启动类:
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);
}
}
AI写代码java
运行
1234567891011
测试类:
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 products1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
assertThat(products1).hasSize(5);
// 第二次访问,从缓存获取
List 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();
}
}
AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142
✅ 结论:集成Spring Cache的步骤包括创建Spring Boot项目、添加所需的依赖、配置缓存、创建业务层、创建控制器类、测试应用。
31.3.2 集成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>
AI写代码xml
1234567891011121314151617181920212223242526
application.properties文件中的配置:
# 服务器端口
server.port=8080
# Redis连接信息
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0
AI写代码properties
12345678
实体类:
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 +
'}';
}
}
AI写代码java
运行
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
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() {
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(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));
}
}
AI写代码java
运行
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
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);
}
}
AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445
控制器类:
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);
}
}
AI写代码java
运行
12345678910111213141516171819202122232425262728293031323334353637
应用启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class RedisCacheApplication {
public static void main(String[] args) {
SpringApplication.run(RedisCacheApplication.class, args);
}
}
AI写代码java
运行
1234567891011
测试类:
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 RedisCacheApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
}
@Test
void testGetAllProducts() {
List products1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
assertThat(products1).hasSize(5);
List 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();
}
}
AI写代码java
运行
1234567891011121314151617181920212223242526272829303132333435363738
✅ 结论:集成Redis缓存的步骤包括创建Spring Boot项目、添加所需的依赖、配置Redis、创建业务层、创建控制器类、测试应用。
31.4 Spring Boot的实际应用场景
在实际开发中,Spring Boot缓存与性能优化的应用场景非常广泛,如:
- 实现产品信息的缓存优化。
- 实现用户信息的缓存优化。
- 实现订单信息的缓存优化。
- 实现支付信息的缓存优化。
示例:
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
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.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Repository
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(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));
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/products")
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);
}
}
@SpringBootApplication
@EnableCaching
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
// 测试类
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class CacheApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {
}
@Test
void testGetAllProducts() {
List products1 = restTemplate.getForObject("http://localhost:" + port + "/api/products/", List.class);
assertThat(products1).hasSize(5);
List 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();
}
}
AI写代码java
运行
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
输出结果:
- 第一次访问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的其他组件、微服务等内容。