@Cacheable
是 Spring 框架中用于缓存的注解之一,它可以帮助你轻松地将方法的结果缓存起来,从而提高应用的性能。下面详细介绍如何使用 @Cacheable
注解以及相关的配置和注意事项。
1. 基本用法
1.1 添加依赖
首先,确保你的项目中包含了 Spring Cache 的依赖。如果你使用的是 Spring Boot,可以在 pom.xml
或 build.gradle
中添加以下依赖:
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Gradle:
implementation 'org.springframework.boot:spring-boot-starter-cache'
1.2 启用缓存
在你的 Spring Boot 应用的主类或配置类上添加 @EnableCaching
注解,以启用缓存功能。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1.3 使用 @Cacheable
注解
假设你有一个服务类 DataService
,其中有一个方法 getSortedData
需要缓存其结果。你可以使用 @Cacheable
注解来实现这一点。
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class DataService {
@Cacheable("sortedData")
public TableDataInfo getSortedData(String param) {
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 返回模拟数据
return new TableDataInfo();
}
}
解释:
@Cacheable("sortedData")
: 这个注解告诉 Spring 在调用getSortedData
方法时,先检查名为sortedData
的缓存中是否存在与参数param
对应的结果。- 如果存在,则直接返回缓存中的结果,不再执行方法体。
- 如果不存在,则执行方法体,将结果存入缓存中,并返回结果。
1.4 自定义缓存键
默认情况下,Spring 使用方法参数作为缓存键。如果你需要自定义缓存键,可以使用 key
属性。
@Cacheable(value = "sortedData", key = "#param")
public TableDataInfo getSortedData(String param) {
// 方法体
}
解释:
key = "#param"
: 使用方法参数param
作为缓存键。
你还可以使用 SpEL(Spring Expression Language)来构建更复杂的缓存键。
@Cacheable(value = "sortedData", key = "#param + '_' + #anotherParam")
public TableDataInfo getSortedData(String param, String anotherParam) {
// 方法体
}
2. 配置缓存管理器
Spring 支持多种缓存实现,如 Caffeine、Ehcache、Redis 等。下面分别介绍如何配置这些缓存管理器。
2.1 使用 Caffeine 作为缓存实现
-
添加依赖:
<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency>
-
配置 Caffeine:
你可以在
application.yml
或application.properties
中配置 Caffeine 的缓存参数。application.yml:
spring: cache: type: caffeine caffeine: spec: maximumSize=1000,expireAfterAccess=60s
application.properties:
spring.cache.type=caffeine spring.cache.caffeine.spec=maximumSize=1000,expireAfterAccess=60s
maximumSize=1000
: 设置缓存的最大条目数为 1000。expireAfterAccess=60s
: 设置缓存条目在最后一次访问后的过期时间为 60 秒。
2.2 使用 Ehcache 作为缓存实现
-
添加依赖:
<dependency> <groupId>org.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency>
-
配置 Ehcache:
创建一个
ehcache.xml
文件,并在其中定义缓存配置。ehcache.xml:
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.ehcache.org/v3' xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd"> <cache alias="sortedData"> <key-type>java.lang.String</key-type> <value-type>com.ruoyi.common.core.page.TableDataInfo</value-type> <resources> <heap unit="entries">1000</heap> <offheap unit="MB">100</offheap> </resources> </cache> </config>
<heap unit="entries">1000</heap>
: 设置堆内存中缓存的最大条目数为 1000。<offheap unit="MB">100</offheap>
: 设置堆外内存中缓存的最大大小为 100MB。
-
配置 Spring 使用 Ehcache:
在
application.yml
或application.properties
中指定 Ehcache 配置文件的位置。application.yml:
spring: cache: type: ehcache ehcache: config: classpath:ehcache.xml
application.properties:
spring.cache.type=ehcache spring.cache.ehcache.config=classpath:ehcache.xml
2.3 使用 Redis 作为缓存实现
-
添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
配置 Redis:
在
application.yml
或application.properties
中配置 Redis 连接信息。application.yml:
spring: cache: type: redis redis: host: localhost port: 6379
application.properties:
spring.cache.type=redis spring.redis.host=localhost spring.redis.port=6379
-
可选配置:
你可以进一步配置 Redis 的缓存行为,例如设置最大内存大小和淘汰策略。
application.yml:
spring: redis: lettuce: pool: max-active: 20 max-idle: 10 min-idle: 5 timeout: 5000ms
3. 其他相关注解
除了 @Cacheable
,Spring 还提供了其他几个注解来管理缓存:
3.1 @CachePut
@CachePut
注解用于更新缓存中的值,但不会影响方法的执行。每次调用带有 @CachePut
注解的方法时,都会执行方法体并将结果存入缓存。
@CachePut(value = "sortedData", key = "#param")
public TableDataInfo updateSortedData(String param) {
// 更新逻辑
return new TableDataInfo();
}
3.2 @CacheEvict
@CacheEvict
注解用于从缓存中移除一个或多个条目。适用于需要清除缓存的情况。
@CacheEvict(value = "sortedData", key = "#param")
public void deleteSortedData(String param) {
// 删除逻辑
}
// 清除整个缓存
@CacheEvict(value = "sortedData", allEntries = true)
public void clearAllSortedData() {
// 清除所有缓存
}
3.3 @Caching
@Caching
注解允许你在同一个方法上组合多个缓存操作。
@Caching(
put = {
@CachePut(value = "sortedData", key = "#param"),
@CachePut(value = "anotherCache", key = "#param")
},
evict = {
@CacheEvict(value = "oldCache", key = "#param")
}
)
public TableDataInfo updateAndEvict(String param) {
// 更新逻辑
return new TableDataInfo();
}
4. 示例代码
下面是一个完整的示例,展示了如何使用 @Cacheable
注解以及配置 Caffeine 缓存。
4.1 项目结构
src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ ├── Application.java
│ │ ├── config
│ │ │ └── CacheConfig.java
│ │ ├── service
│ │ │ └── DataService.java
│ │ └── model
│ │ └── TableDataInfo.java
│ └── resources
│ └── application.yml
java_303">4.2 Application.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
java_320">4.3 CacheConfig.java
package com.example.config;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("sortedData");
cacheManager.setCaffeine(caffeineCacheBuilder());
return cacheManager;
}
Caffeine<Object, Object> caffeineCacheBuilder() {
return Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.SECONDS)
.maximumSize(1000);
}
}
java_352">4.4 DataService.java
package com.example.service;
import com.example.model.TableDataInfo;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class DataService {
@Cacheable("sortedData")
public TableDataInfo getSortedData(String param) {
// 模拟耗时操作
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 返回模拟数据
return new TableDataInfo();
}
}
java_377">4.5 TableDataInfo.java
package com.example.model;
public class TableDataInfo {
// 模拟数据模型
}
4.6 application.yml
spring:
cache:
type: caffeine
5. 注意事项
-
缓存一致性:
- 确保在更新数据时正确使用
@CachePut
和@CacheEvict
注解,以保持缓存的一致性。 - 对于分布式系统,考虑使用支持分布式缓存的实现(如 Redis)。
- 确保在更新数据时正确使用
-
缓存失效策略:
- 根据业务需求选择合适的缓存失效策略(如基于时间、基于条件等)。
- 定期清理过期或不必要的缓存条目,以避免内存泄漏。
-
缓存击穿和穿透:
- 缓存击穿: 当缓存失效后,大量请求同时涌入数据库,导致数据库压力骤增。
- 解决方案: 可以使用互斥锁(如 Redis 分布式锁)来防止缓存击穿。
- 缓存穿透: 当查询一个不存在的数据时,所有请求都直接打到数据库。
- 解决方案: 可以在缓存中存储一个空对象或特殊标记,表示该数据不存在。
- 缓存击穿: 当缓存失效后,大量请求同时涌入数据库,导致数据库压力骤增。
-
缓存雪崩:
- 当大量缓存同时失效时,大量请求直接打到数据库,导致数据库压力骤增。
- 解决方案: 可以设置不同的过期时间,避免缓存同时失效。
6. 调试和监控
为了更好地管理和调试缓存,可以使用以下工具和方法:
- 日志记录: 在方法上添加日志记录,查看缓存的命中率和缓存操作的频率。
- 监控工具: 使用监控工具(如 Prometheus、Grafana)来监控缓存的性能指标。
- Spring Boot Actuator: 提供了缓存相关的端点,可以方便地查看缓存的状态和统计信息。
启用 Spring Boot Actuator:
-
添加依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
配置暴露端点:
application.yml:
management: endpoints: web: exposure: include: "caches"
-
访问缓存端点:
访问
http://localhost:8080/actuator/caches
可以查看缓存的状态信息。
总结
通过使用 @Cacheable
注解,可以轻松地在 Spring 应用中实现缓存机制,从而提高应用的性能和响应速度。结合不同的缓存实现(如 Caffeine、Ehcache、Redis),你可以根据具体需求灵活配置缓存策略,确保缓存的有效性和高效性。