本文主要内容:
1. Spring 缓存抽象定义及相关概念
2. @Cacheable,@CachePut, @CacheEvict, @CacheConfig使用
3.基于Redis的缓存实现
1. Spring 缓存抽象定义及相关概念
1. Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用Java
Caching(JSR-107)注解简化我们进行缓存开发
JSR-107中定义了5个核心接口,分别是CachingProvider(缓存提供者)、CacheManager(缓存管理者)、Cache(缓存)、Entry(缓存键值对)和Expiry(缓存时效)
Spring Cache只负责抽象层,Cache 实现有:RedisCache、EhCacheCache、
ConcurrentMapCache等
在SpringBoot自动装配过程中,创建了CacheMamager对象,默认情况下使用SimpleCacheConfiguration 向IOC容器中注入ConcurrentMapCacheManager (CacheMamager)
Cache底层数据结构为 ConcurrentHashMap
2. @Cacheable,@CachePut, @CacheEvict, @CacheConfig使用
1. 开启缓存 @EnableCaching
.....
@EnableCaching
public class MySpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MySpringBootDemoApplication.class, args);
}
}
2, @Cacheable,@CachePut, @CacheEvict
@Cacheable将方法运行的结果进行缓存,后期再获取相同的数据时,直接从缓存中获取,不再调用方法
属性信息包含
***** 既满足condition又满足unless条件的也不进行缓存
**** 使用异步模式进行缓存时(sync=true):unless条件将不被支持
@CachePut 调用方法,之后将方法的结果放入缓存 (可用于 更新操作时,更新缓存数据)
@CacheEvict 缓存清除,清除缓存时要指明缓存的名字和key( key默认为参数的值 )
***** 在使用过程中,@CachePut 和 @CacheEvict 修改和删除缓存,要保证cacheNames和key能对应到相应的缓存信息;
如下
@Cacheable(cacheNames = "user", key = "#id") public User findById(Integer id) { return userMapper.findById(id); } @CachePut(cacheNames = "user", key = "#user.id") public User update(User user) { userMapper.update(user); return user; } @CacheEvict(cacheNames = "user", key = "#id") public void delete(Integer id) { userMapper.delete(id); }
附:常用spEL表达式
3. @CacheConfig 标注在类上,抽取缓存相关注解的公共配置,可抽取的公共配置有缓存名字、主键生成器等(如注解中的属性所示)
包含属性 cacheNames keyGenerator cacheManager cacheResolver
@CacheConfig(cacheNames = "user") public class UserServiceImpl implements UserService { ....... @Cacheable( key = "#id") public User findById(Integer id) { return userMapper.findById(id); } @CachePut( key = "#user.id") public User update(User user) { userMapper.update(user); return user; } @CacheEvict(key = "#id") public void delete(Integer id) { userMapper.delete(id); } }
3.基于Redis的缓存实现
1. 添加spring-boot-redis-starter依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2. 实体类需要 可序列化
public class User implements Serializable {
3. redis配置
spring.redis.host=127.0.0.1 spring.redis.database=1
参考其配置类
@ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { /** * Database index used by the connection factory. */ private int database = 0; /** * Connection URL. Overrides host, port, and password. User is ignored. Example: * redis://user:password@example.com:6379 */ private String url; /** * Redis server host. */ private String host = "localhost"; /** * Login password of the redis server. */ private String password; /** * Redis server port. */ private int port = 6379; /** * Whether to enable SSL support. */ private boolean ssl; /** * Connection timeout. */ private Duration timeout; /** * Client name to be set on connections with CLIENT SETNAME. */ private String clientName; private Sentinel sentinel; private Cluster cluster;................
4.自定义RedisCacheManager,设置序列化方式为格式 (SpringBoot默认采用的是JDK的对象序列化方式)
@Configuration public class RedisConfig { @Bean public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { // 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换 RedisSerializer<String> strSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class); // 解决查询缓存转换异常的问题 ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); // 定制缓存数据序列化方式及时效 RedisCacheConfiguration config = RedisCacheConfiguration .defaultCacheConfig() .entryTtl(Duration.ofDays(1)) // 设置key的序列化方式 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer)) // 设置value的序列化方式 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jacksonSeial)) .disableCachingNullValues(); RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(config).build(); return cacheManager; } }