springboot的原⽣cache_详解SpringBoot的三种缓存技术
(Spring。。。
引⾔
前两天在写⼀个实时数据处理的项⽬,项⽬要求是 1s 要处理掉 1k 的数据,这时候显然光靠查数据库是不⾏的,技术选型的时候⽼⼤跟我提了⼀下使⽤ Layering-Cache 这个开源项⽬来做缓存框架。
之间问了⼀下⾝边的⼩伙伴,似乎对这块了解不多。⼀般也就⽤⽤ Redis 来缓存,应该是很少⽤多级缓存框架来专门性的管理缓存吧。
趁着这个机会,我多了解了⼀些关于 SpringBoot 中缓存的相关技术,于是有了这篇⽂章!
在项⽬性能需求⽐较⾼时,就不能单单依赖数据库访问来获取数据了,必须引⼊缓存技术。
常⽤的有本地缓存、Redis 缓存。
本地缓存:也就是内存,速度快,缺点是不能持久化,⼀旦项⽬关闭,数据就会丢失。⽽且不能满⾜分布式系统的应⽤场景(⽐如数据不⼀致的问题)。
Redis 缓存:也就是利⽤数据库等,最常见的就是 Redis。Redis 的访问速度同样很快,可以设置过期时间、设置持久化⽅法。缺点是会受到⽹络和并发访问的影响。
本节介绍三种缓存技术:Spring Cache、Layering Cache 框架、Alibaba JetCache 框架。⽰例使⽤的 SpringBoot 版本是
2.1.
3.RELEASE。⾮ SpringBoot 项⽬请参考⽂章中给出的⽂档地址。
⼀、Spring Cache
Spring Cache 是 Spring ⾃带的缓存⽅案,使⽤简单,既可以使⽤本地缓存,也可以使⽤ Redis
CacheType 包括:
GENERIC, JCACHE, EHCACHE, HAZELCAST, INFINISPAN, COUCHBASE, REDIS, CAFFEINE, SIMPLE, NONE
Spring Cache 的使⽤很简单,引⼊ 即可,我这⾥使⽤创建的是⼀个 web 项⽬,引⼊的 `spring-boot-starter-web` 包含了 。
这⾥利⽤ Redis 做缓存,再引⼊ spring-boot-starter-data-redis依赖:
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
在配置类 or Application 类上添加 @EnableCaching 注解以启动缓存功能。
配置⽂件很简洁(功能也⽐较少):
server:
port: 8081
servlet:
context-path: /api
spring:
cache:
type: redis
redis:
host: 127.0.0.1
port: 6379
database: 1
下⾯我们编写⼀个对 User 进⾏增删改查的 Controller,实现对 User 的 save/delete/findAll 三个操作。为演⽰⽅便,DAO 层不接⼊数据库,⽽是使⽤ HashMap 来直接模拟数据库操作。
我们直接看 service 层的接⼝实现:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
@Cacheable(value = "user", key = "#userId")
public User findById(Integer userId) {
return userDAO.findById(userId);
}
@Override
@CachePut(value = "user", key = "#user.id", condition = "#user.id != null")
public User save(User user) {
spring aop应用场景user.setUpdateTime(new Date());
userDAO.save(user);
return userDAO.Id());
}
@Override
@CacheEvict(value = "user", key = "#userId")
public boolean deleteById(Integer userId) {
return userDAO.deleteById(userId);
}
@Override
public List findAll() {
return userDAO.findAll();
}
}
我们可以看到使⽤了 @Cacheable、@CachePut、@CacheEvict 注解。
Cacheable:启⽤缓存,⾸先从缓存中查数据,如果存在,则从缓存读取数据;如果不存在,则执⾏⽅法,并将⽅法返回值添加到缓存
@CachePut:更新缓存,如果 condition 计算结果为 true,则将⽅法返回值添加到缓存中
@CacheEvict:删除缓存,根据 value 与 key 字段计算缓存地址,将缓存数据删除
测试发现默认的对象存到 Redis 后是 binary 类型,我们可以通过修改 RedisCacheConfiguration 中的序列化规则去调整。⽐如:
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration =
configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(D
return configuration;
}
}
Spring Cache 的功能⽐较单⼀,例如不能实现缓存刷新、⼆级缓存等功能。下⾯介绍⼀个开源项⽬:Layering-Cache,该项⽬实现了缓
存刷新、⼆级缓存(⼀级内存、⼆级 Redis)。同时较容易扩展实现为⾃⼰的缓存框架。
⼆、Layering Cache 框架
引⼊依赖:
com.github.xiaolyuh
layering-cache-starter
2.0.7
配置⽂件不需要做什么修改。启动类依然加上 @EnableCaching 注解。
然后需要配置⼀下 RedisTemplate:
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
return createRedisTemplate(redisConnectionFactory);
}
public RedisTemplate createRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使⽤Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//Map
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
下⾯我们使⽤ layering 包中的 @Cacheable @CachePut @CatchEvict 三个注解来替换 Spring Cache 的默认注解。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDAO userDAO;
@Override
//@Cacheable(value = "user", key = "#userId")
@Cacheable(value = "user", key = "#userId",
firstCache = @FirstCache(expireTime = 5, timeUnit = TimeUnit.MINUTES),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3, forceRefresh = true, isAllowNullValue = true, timeUnit = TimeUnit.MINUTES))
public User findById(Integer userId) {
return userDAO.findById(userId);
}
@Override
//@CachePut(value = "user", key = "#user.id", condition = "#user.id != null")
@CachePut(value = "user", key = "#user.id",
firstCache = @FirstCache(expireTime = 5, timeUnit = TimeUnit.MINUTES),
secondaryCache = @SecondaryCache(expireTime = 10, preloadTime = 3, forceRefresh = true, isAllowNullValue = true, timeUnit = TimeUnit.MINUTES))
public User save(User user) {
user.setUpdateTime(new Date());
userDAO.save(user);
return userDAO.Id());
}
@Override
//@CacheEvict(value = "user", key = "#userId")
@CacheEvict(value = "user", key = "#userId")
public boolean deleteById(Integer userId) {
return userDAO.deleteById(userId);
}
@Override
public List findAll() {
return userDAO.findAll();
}
}
三、Alibaba JetCache 框架
JetCache是⼀个基于Java的缓存系统封装,提供统⼀的API和注解来简化缓存的使⽤。 JetCache提供了⽐SpringCache更加强⼤的注解,可以原⽣的⽀持TTL、两级缓存、分布式⾃动刷新,还提供了Cache接⼝⽤于⼿⼯缓存操作。 当前有四个实现,RedisCache、TairCache(此部分未在github开源)、CaffeineCache(in memory)和⼀个简易的LinkedHashMapCache(in memory),要添加新的实现也是⾮常简单的。
全部特性:
通过统⼀的API访问Cache系统
通过注解实现声明式的⽅法缓存,⽀持TTL和两级缓存
通过注解创建并配置Cache实例
针对所有Cache实例和⽅法缓存的⾃动统计
Key的⽣成策略和Value的序列化策略是可以配置的
分布式缓存⾃动刷新,分布式锁 (2.2+)
异步Cache API (2.2+,使⽤Redis的lettuce客户端时)
Spring Boot⽀持
SpringBoot 项⽬中,引⼊如下依赖:
com.alicp.jetcache
jetcache-starter-redis
2.5.14
配置:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论