准备工作

* 使用spring boot搭建简单的项目
*
引入redis的包
compile('org.springframework.boot:spring-boot-starter-data-redis')
*
配置application.yml文件,添加如下内容(redis其他可以先使用默认配置)
spring: cache: type: redis redis: database: 0
源码分析

* 在需要缓存的方法上面加上@Cacheable
*
当请求进来的时候会触发CacheInterceptor拦截器,调用invoke方法
@Override public Object invoke(final MethodInvocation invocation) throws
Throwable { Method method = invocation.getMethod(); CacheOperationInvoker
aopAllianceInvoker =new CacheOperationInvoker() { @Override public Object invoke
() {try { return invocation.proceed(); } catch (Throwable ex) { throw new
ThrowableWrapper(ex); } } };try { return execute(aopAllianceInvoker,
invocation.getThis(), method, invocation.getArguments()); }catch
(CacheOperationInvoker.ThrowableWrapper th) {throw th.getOriginal(); } }
*
invoke方法会去调用CacheAspectSupport的execute方法
protected Object execute(CacheOperationInvoker invoker, Object target, Method
method, Object[] args) {// Check whether aspect is enabled (to cope with cases
where the AJ is pulled in automatically) if (this.initialized) { Class<?>
targetClass = getTargetClass(target); Collection<CacheOperation> operations =
getCacheOperationSource().getCacheOperations(method, targetClass);if
(!CollectionUtils.isEmpty(operations)) {return execute(invoker, method, new
CacheOperationContexts(operations, method, args, target, targetClass)); } }
return invoker.invoke(); }
*
然后会调用到cachemanager的getCache方法
@Override public Cache getCache(String name) { Cache cache = this
.cacheMap.get(name);if (cache != null) { return cache; } else { // Fully
synchronize now for missing cache creation... synchronized (this.cacheMap) {
cache =this.cacheMap.get(name); if (cache == null) {
//cache不存在时,会调用该方法取cache,该方法由子类实现 cache = getMissingCache(name); if (cache !=
null) { cache = decorateCache(cache); this.cacheMap.put(name, cache);
updateCacheNames(name); } }return cache; } } }
*
再看RedisCacheManager类
@Override protected Cache getMissingCache(String name) { return this.dynamic ?
createCache(name) :null; } @SuppressWarnings("unchecked") protected RedisCache
createCache(String cacheName) { long expiration = computeExpiration(cacheName);
return new RedisCache(cacheName, (usePrefix ? cachePrefix.prefix(cacheName) :
null), redisOperations, expiration, cacheNullValues); } // 根据cacheName取过期时间
protected long computeExpiration(String name) { Long expiration = null; if
(expires !=null) { expiration = expires.get(name); } return (expiration != null
? expiration.longValue() : defaultExpiration); }
代码实现

* 分析源码后,我们可以在createCache方法上做文章,实现自己的cacheManager
代码如下:
import org.springframework.data.redis.cache.RedisCache; import
org.springframework.data.redis.cache.RedisCacheManager;import
org.springframework.data.redis.core.RedisOperations;import
org.springframework.util.Assert;/** * @author zhangminglei */ public class
CustomizeRedis extends RedisCacheManager { CustomizeRedis(RedisOperations
redisOperations) {super(redisOperations); } @Override protected RedisCache
createCache(String cacheName) { Assert.hasText(cacheName, "CacheName must not
be null or empty!"); String[] values = cacheName.split("#"); long expiration =
computeExpiration(values);return new RedisCache(values[0], (isUsePrefix() ?
getCachePrefix().prefix(cacheName) :null), getRedisOperations(), expiration,
false); } private long computeExpiration(String[] values) { if (values.length >
1) { return Long.parseLong(values[1]); } //
如果说想使用默认的过期时间而不指定特殊时间,则可以直接@Cacheable(cacheNames="name"),不需要加'#过期时间'了 return
super.computeExpiration(values[0]); } }
* 然后需要让cache使用我们的自定义CacheManager //
为redis设定默认的序列化方式为StringRedisSerializer(默认为JdkSerializationRedisSerializer,不太方便查看内容)
@Bean RedisTemplate redisTemplate(RedisConnectionFactory
redisConnectionFactory) { RedisTemplate redisTemplate =new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setDefaultSerializer(new StringRedisSerializer()); return
redisTemplate; }@Bean public RedisCacheManager cacheManager
(RedisTemplate<Object, Object> redisTemplate) { RedisCacheManager cacheManager =
new CustomizeRedis(redisTemplate); cacheManager.setUsePrefix(false);
//设置默认的过期时间,单位秒 cacheManager.setDefaultExpiration(60); //
还可以使用下面的方法为指定的key设定过期时间,它将会在computeExpiration方法中用到 // Map<String, Long> expires
= new HashMap<>(); // expires.put("cacheNameKey", 20L); // expires.put("myKey",
40L); // cacheManager.setExpires(expires); return cacheManager; }
测试代码
//指定cacheNameKey的缓存45秒后过期 @Cacheable(cacheNames = "cacheNameKey#45", key =
"#key") public String testRedisCache(String key) { System.out.println(key);
return "12345"; }

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信