个人主页: 【⭐️个人主页】
需要您的【 点赞+关注】支持
本文核心知识点:
本章使用的spring版本
spring boot version
: 3.1.5
- 缓存抽象的作用
- spring缓存的声明式注解
- spring缓存的生成key策略和如何自定义keyGenerator
- 缓存支持的后端类型
Spring 缓存注解 | 说明 |
---|---|
@Cacheable |
触发缓存填充。 |
@CacheEvict |
触发缓存退出。 |
@CachePut |
在不干扰方法执行的情况下更新缓存。 |
@Caching |
将多个缓存操作重新组合到一个方法上。 |
@CacheConfig |
在类级别共享一些常见的与缓存相关的设置。 |
Spring 缓存注解 | JSR-107 | 备注 |
---|---|---|
@Cacheable |
@CacheResult |
相当相似。 可以缓存特定的异常并强制 无论缓存的内容如何,都执行该方法。@CacheResult |
@CachePut |
@CachePut |
当 Spring 使用方法调用的结果更新缓存时,JCache 要求将其作为注释的参数传递。 由于这种差异,JCache 允许在 实际方法调用。@CacheValue |
@CacheEvict |
@CacheRemove |
相当相似。 支持有条件逐出,当 方法调用会导致异常。@CacheRemove |
@CacheEvict(allEntries=true) |
@CacheRemoveAll |
看。@CacheRemove |
@CacheConfig |
@CacheDefaults |
允许您以类似的方式配置相同的概念。 |
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root对象 | 当前被调用的方法名 | #root.methodname |
method | root对象 | 当前被调用的方法 | #root.method.name |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
Argument Name | 执行上下文 | 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 | #artsian.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
implementation 'org.springframework.boot:spring-boot-starter-cache'
添加启用缓存注解@EnableCaching
@SpringBootApplication(scanBasePackages = {"com.kongxiang"})
@EnableAutoConfiguration
@EnableCaching
public class StudySpring3Application {
public static void main(String[] args) {
SpringApplication.run(StudySpring3Application.class, args);
}
}
spring cache支持的缓存类型
查看类org.springframework.boot.autoconfigure.cache.CacheType
public enum CacheType {
/**
* Generic caching using 'Cache' beans from the context.
*/
GENERIC,
/**
* JCache (JSR-107) backed caching.
*/
JCACHE,
/**
* Hazelcast backed caching.
*/
HAZELCAST,
/**
* Couchbase backed caching.
*/
COUCHBASE,
/**
* Infinispan backed caching.
*/
INFINISPAN,
/**
* Redis backed caching.
*/
REDIS,
/**
* Cache2k backed caching.
*/
CACHE2K,
/**
* Caffeine backed caching.
*/
CAFFEINE,
/**
* Simple in-memory caching.
*/
SIMPLE,
/**
* No caching.
*/
NONE
}
无缓存
spring:
cache:
type: NONE
内存缓存
spring:
cache:
type: SIMPLE
Redis 缓存
spring:
cache:
type: REDIS
data:
redis:
host: '127.0.0.1'
username:
port: 6379
password:
database: 1
lettuce:
pool:
enabled: true
max-active: 8
max-wait: 1000
max-idle: 8
connect-timeout: 5000
默认情况下会有两个模板类被注入Spring IoC
供我们使用,需要个性化配置
来满足实际的开发。
一个是RedisTemplate
,主要用于对象缓存
,其默认使用JDK序列化
,我们需要更改其序列化方式
解决一些问题,比如Java 8日期问题
、JSON序列化
问题。需要我们重写一下。
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = initJacksonSerializer();
// 设置value的序列化规则和 key的序列化规则
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
/**
* 处理redis序列化问题
* @return Jackson2JsonRedisSerializer
*/
private Jackson2JsonRedisSerializer<Object> initJacksonSerializer() {
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//以下替代旧版本 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
//bugFix Jackson2反序列化数据处理LocalDateTime类型时出错
om.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
// java8 时间支持
om.registerModule(new JavaTimeModule());
return new Jackson2JsonRedisSerializer<>(om,Object.class);
}
我们通过向Spring IoC分别注入RedisCacheConfiguration
和RedisCacheManagerBuilderCustomizer
来个性化配置
/**
* Redis cache configuration.
*
* @param redisTemplate the redis template
* @return the redis cache configuration
*/
@Bean
public RedisCacheConfiguration redisCacheConfiguration(RedisTemplate<Object, Object> redisTemplate, CacheProperties cacheProperties) {
// 参见 spring.cache.redis
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
// 缓存的序列化问题
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(redisTemplate.getValueSerializer()));
if (redisProperties.getTimeToLive() != null) {
// 全局 TTL 时间
redisCacheConfiguration = redisCacheConfiguration.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
// key 前缀值
redisCacheConfiguration = redisCacheConfiguration.prefixCacheNameWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
// 默认缓存null值 可以防止缓存穿透
redisCacheConfiguration = redisCacheConfiguration.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
// 不使用key前缀
redisCacheConfiguration = redisCacheConfiguration.disableKeyPrefix();
}
return redisCacheConfiguration;
}
/**
* Redis cache manager 个性化配置缓存过期时间.
*
* @return the redis cache manager builder customizer
*/
@Bean
public RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer(RedisCacheConfiguration redisCacheConfiguration) {
return builder -> builder.cacheDefaults(redisCacheConfiguration);
}
引入依赖
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
修改配置
spring:
cache:
type: CAFFEINE
直接启动即可
spring cache 缓存抽象加上spring data包和spring boot autoconfig 配置包的能力,可以快速接入一个具体的缓存实现。redis是我们公司基本使用的缓存策略。所以针对redis的一些自定义配置,通过 java bean的方式实现。着重强调一下。