-
Notifications
You must be signed in to change notification settings - Fork 336
xiaolyuh123 edited this page Aug 2, 2024
·
42 revisions
表示该方法的结果是可以被缓存的,当该方法被调用时先检查缓存是否命中,如果没有命中再调用被缓存的方法,并将其返回值放到缓存中。
名称 | 默认值 | 说明 |
---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 |
cacheNames | 空字符串数组 | 缓存名称 |
key | 空字符串 | 缓存key,支持SpEL表达式 |
depict | 空字符串 | 缓存描述(在缓存统计页面会用到) |
cacheMode | CacheMode.ALL | 缓存模式(只使用一级缓存或者二级缓存) |
firstCache | 一级缓存配置 | |
secondaryCache | 二级缓存配置 |
表示该方法的结果是可以被批量缓存的,当该方法被调用时先检查单条key缓存是否命中,如果命中直接走缓存,剩下的没有命中的key再调用被缓存的方法,并将其返回值批量放到缓存中。
特别提醒:
- 方法返回值必须是List结构。
- keys的EL表达式必须能同时应用与参数和返回值,比如
keys = "#users.![userId]"
中的id需要保证参数和返回值同时都能取到值。
名称 | 默认值 | 说明 |
---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 |
cacheNames | 空字符串数组 | 缓存名称 |
keys | 必填,无默认值 | 缓存keys,需要是SpEL表达式。这个表达式会用于从参数和返回值中获取数据对应缓存keys |
depict | 空字符串 | 缓存描述(在缓存统计页面会用到) |
cacheMode | CacheMode.ALL | 缓存模式(只使用一级缓存或者二级缓存) |
firstCache | 一级缓存配置 | |
secondaryCache | 二级缓存配置 |
一级缓存配置项
名称 | 默认值 | 说明 |
---|---|---|
initialCapacity | 10 | 缓存初始Size |
maximumSize | 5000 | 缓存最大Size |
expireTime | 9 | 缓存有效时间 |
timeUnit | TimeUnit.MINUTES | 时间单位,默认分钟 |
expireMode | ExpireMode.WRITE | 缓存失效模式,ExpireMode.WRITE:最后一次写入后到期失效,ExpireMode.ACCESS:最后一次访问后到期失效 |
二级缓存配置项
名称 | 默认值 | 说明 |
---|---|---|
expireTime | 5 | 缓存有效时间 |
preloadTime | 1 | 缓存主动在失效前强制刷新缓存的时间,建议是 expireTime * 0.2 |
timeUnit | TimeUnit.HOURS | 时间单位,默认小时 |
forceRefresh | false | 是否强制刷新(直接执行被缓存方法) |
magnification | 1 | 非空值和null值之间的时间倍率,默认是1。如expireTime=60秒,magnification=10,那么当缓存空值时,空值的缓存过期时间是60/10=6秒。 |
将数据放到缓存中
名称 | 默认值 | 说明 |
---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 |
cacheNames | 空字符串数组 | 缓存名称 |
key | 空字符串 | 缓存key,支持SpEL表达式 |
depict | 空字符串 | 缓存描述(在缓存统计页面会用到) |
cacheMode | CacheMode.ALL | 缓存模式(只使用一级缓存或者二级缓存) |
firstCache | 一级缓存配置 | |
secondaryCache | 二级缓存配置 |
删除缓存
名称 | 默认值 | 说明 |
---|---|---|
value | 空字符串数组 | 缓存名称,cacheNames的别名 |
cacheNames | 空字符串数组 | 缓存名称 |
key | 空字符串 | 缓存key,支持SpEL表达式 |
allEntries | false | 是否删除缓存中所有数据,默认情况下是只删除关联key的缓存数据,当该参数设置成 true 时 key 参数将无效 |
cacheMode | CacheMode.ALL | 缓存模式(只使用一级缓存或者二级缓存) |
async | false | 是否异步删除缓存中所有数据 |
同时使用多个缓存注解
名称 | 默认值 | 说明 |
---|---|---|
cacheable | Cacheable数组 | Cacheable注解 |
put | CachePut数组 | CachePut注解 |
evict | CacheEvict数组 | CacheEvict注解 |
- 引入layering-cache
<dependency>
<groupId>com.github.xiaolyuh</groupId>
<artifactId>layering-cache-starter</artifactId>
<version>${layering.version}</version>
</dependency>
- 添加配置
server.port=8082
#layering-cache 配置
layering-cache.stats=true
# 缓存命名空间,如果不配置取 "spring.application.name"
layering-cache.namespace=layering-cache-web
layering-cache.redis.database=0
layering-cache.redis.timeout=60
layering-cache.redis.password=
# redis单机
#layering-cache.redis.host=127.0.0.1
#layering-cache.redis.port=6378
# redis集群
#layering-cache.redis.cluster=127.0.0.1:6379,127.0.0.1:6378
# redis sentinel
layering-cache.redis.sentinel-nodes=127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381
layering-cache.redis.sentinel-master=mymaster
# 设置redis值的序列化方式,默认是kryo
#com.github.xiaolyuh.redis.serializer.KryoRedisSerializer
#com.github.xiaolyuh.redis.serializer.FastJsonRedisSerializer
#com.github.xiaolyuh.redis.serializer.JacksonRedisSerializer
#com.github.xiaolyuh.redis.serializer.JdkRedisSerializer
#com.github.xiaolyuh.redis.serializer.ProtostuffRedisSerializer
layering-cache.redis.serializer=com.github.xiaolyuh.redis.serializer.KryoRedisSerializer
- 配置类中添加注解
@EnableLayeringCache
启用layering-cache
@SpringBootApplication
@EnableLayeringCache
public class LayeringCacheStartDemoApplication {
public static void main(String[] args) {
SpringApplication.run(LayeringCacheStartDemoApplication.class, args);
}
}
- 引入layering-cache
- maven 方式
<dependency>
<groupId>com.github.xiaolyuh</groupId>
<artifactId>layering-cache-aspectj</artifactId>
<version>${layering.version}</version>
</dependency>
- gradle 方式
compile 'com.github.xiaolyuh:layering-cache:${layering.version}'
- RedisClient(可以参考layering-cache-aspectj的Test配置)
@Configuration
@PropertySource({"classpath:application.properties"})
public class RedisConfig {
@Value("${spring.redis.database:0}")
private int database;
@Value("${spring.redis.host:192.168.83.128}")
private String host;
@Value("${spring.redis.password:}")
private String password;
@Value("${spring.redis.port:6378}")
private int port;
@Bean
public RedisClient layeringCacheRedisClient() {
RedisProperties redisProperties = new RedisProperties();
redisProperties.setDatabase(database);
redisProperties.setHost(host);
redisProperties.setPassword(StringUtils.isBlank(password) ? null : password);
redisProperties.setPort(port);
KryoRedisSerializer<Object> kryoRedisSerializer = new KryoRedisSerializer<>(Object.class);
StringRedisSerializer keyRedisSerializer = new StringRedisSerializer();
SingleRedisClient redisClient = new SingleRedisClient(redisProperties);
redisClient.setKeySerializer(keyRedisSerializer);
redisClient.setValueSerializer(kryoRedisSerializer);
return redisClient;
}
}
- 声明CacheManager和LayeringAspect
/**
* 多级缓存配置
*
* @author yuhao.wang3
*/
@Configuration
@Import({RedisConfig.class})
@EnableAspectJAutoProxy
public class CacheConfig {
@Bean
public CacheManager layeringCacheManager(RedisClient layeringCacheRedisClient, CacheStatsReportService cacheStatsReportService, LayeringCacheProperties layeringCacheProperties) {
LayeringCacheManager layeringCacheManager = new LayeringCacheManager(layeringCacheRedisClient);
// 默认开启统计功能
layeringCacheManager.setStats(layeringCacheProperties.isStats());
// 上报缓存统计信息
layeringCacheManager.setCacheStatsReportService(cacheStatsReportService);
// 设置缓存命名空间
GlobalConfig.setNamespace(StringUtils.isBlank(layeringCacheProperties.getNamespace()) ? applicationName : layeringCacheProperties.getNamespace());
return layeringCacheManager;
}
@Bean
@ConditionalOnMissingBean(CacheStatsReportService.class)
public CacheStatsReportService cacheStatsReportService() {
return new DefaultCacheStatsReportServiceImpl();
}
}
直接在需要缓存的方法上加上Cacheable、BatchCacheable、CacheEvict、CachePut、Caching注解。
- Cacheable注解
@Cacheable(value = "user:info", depict = "用户信息缓存", cacheMode = CacheMode.ALL,
firstCache = @FirstCache(expireTime = 4, timeUnit = TimeUnit.SECONDS),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3, forceRefresh = true, timeUnit = TimeUnit.SECONDS))
public User getUser(User user) {
logger.debug("调用方法获取用户名称");
return user;
}
- BatchCacheable注解
特别提醒:
- 方法返回值必须是List结构。
- keys的EL表达式必须能同时应用与参数和返回值,比如
keys = "#users.![userId]"
中的id需要保证参数和返回值同时都能取到值。
@BatchCacheable(value = "user:info", keys = "#users.![userId]", depict = "用户信息缓存",
firstCache = @FirstCache(expireTime = 10, timeUnit = TimeUnit.SECONDS),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3,timeUnit = TimeUnit.SECONDS))
public List<User> getUserByIds(List<User> users) {
logger.debug("测试正常配置的批量缓存方法");
ArrayList<User> res = new ArrayList<>();
for (int i = 0; i < Math.min(users.size(),2) ; i++) {
User user = new User();
user.setUserId(users.get(i).getUserId());
user.setAge(i);
user.setLastName(new String[]{"w", "y", Integer.toString(i)});
res.add(user);
}
return res;
}
- CachePut注解
@CachePut(value = "user:info", key = "#userId", depict = "用户信息缓存", cacheMode = CacheMode.ALL,
firstCache = @FirstCache(expireTime = 4, timeUnit = TimeUnit.SECONDS),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3, forceRefresh = true, timeUnit = TimeUnit.SECONDS))
public User putUser(long userId) {
User user = new User();
user.setUserId(userId);
user.setAge(31);
user.setLastName(new String[]{"w", "y", "h"});
return user;
}
- CacheEvict注解
@CacheEvict(value = "user:info", key = "#userId")
public void evictUser(long userId) {
}
@CacheEvict(value = "user:info", allEntries = true)
public void evictAllUser() {
}
- Caching注解
@Caching(evict = {@CacheEvict(value = "user:info:caching:3-4-0", key = "'evict'+#userId"), @CacheEvict(value = "user:info:caching", allEntries = true)},
put = {@CachePut(value = "user:info:caching:3-4-0", key = "'put'+#userId",
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3, timeUnit = TimeUnit.SECONDS))},
cacheable = {@Cacheable(value = "user:info:caching:3-4-0", key = "#userId",
firstCache = @FirstCache(expireTime = 4, timeUnit = TimeUnit.SECONDS),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 7, timeUnit = TimeUnit.SECONDS))})
public User cachingAll(long userId) {
return user;
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {CacheConfig.class})
public class CacheCoreTest {
private Logger logger = LoggerFactory.getLogger(CacheCoreTest.class);
@Autowired
private CacheManager cacheManager;
@Test
public void testCacheExpiration() {
FirstCacheSetting firstCacheSetting = new FirstCacheSetting(10, 1000, 4, TimeUnit.SECONDS, ExpireMode.WRITE);
SecondaryCacheSetting secondaryCacheSetting = new SecondaryCacheSetting(10, 4, TimeUnit.SECONDS, true);
LayeringCacheSetting layeringCacheSetting = new LayeringCacheSetting(firstCacheSetting, secondaryCacheSetting);
String cacheName = "cache:name";
String cacheKey = "cache:key1";
LayeringCache cache = (LayeringCache) cacheManager.getCache(cacheName, layeringCacheSetting);
cache.get(cacheKey, () -> initCache(String.class));
cache.put(cacheKey, "test");
cache.evict(cacheKey);
cache.clear();
}
private <T> T initCache(Class<T> t) {
logger.debug("加载缓存");
return (T) "test";
}
}
@Resource
private LayeringCacheManager layeringCacheManager;
@PostMapping("/clear-layering-cache")
@ApiOperation(value = "清空layering-cache缓存", httpMethod = "POST")
public Boolean clearLayeringCache(String cacheName) {
LayeringCacheSetting defaultSetting = new LayeringCacheSetting(new FirstCacheSetting(), new SecondaryCacheSetting(), "默认缓存配置(删除时生成)", CacheMode.ALL);
Cache cache = layeringCacheManager.getCache(cacheName, defaultSetting);
cache.clear();
return true;
}