最近项目需要增加缓存功能,由于dao层使用的mybatis,一开始考虑使用mybatis的二级缓存来实现,但是发现针对多表联合的情况下不好实现,所以转战spring cache + redis。
1、增加maven配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2、定义cache config
@Configuration @Slf4j public class CacheManageConfig<K,V> { @Bean public CacheManager cacheManager(RedisTemplate<K,V> redisTemplate) { log.info("-------------------- cacheManager init ---------------------"); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); RedisCacheManager cacheManager = new CustomRedisCacheManager(redisTemplate); cacheManager.setDefaultExpiration(300); return cacheManager; } }
@Slf4j public class CustomRedisCacheManager extends RedisCacheManager{ public CustomRedisCacheManager(RedisOperations redisOperations) { super(redisOperations); } @Override public Cache getCache(String name) { return new RedisCacheWrapper(super.getCache(name)); } }
@Slf4j public class RedisCacheWrapper implements Cache { private final Cache delegate; public RedisCacheWrapper(Cache redisCache) { this.delegate = redisCache; } @Override public String getName() { try { return delegate.getName(); } catch (Exception e) { log.warn("redis异常,缓存功能失效..."); return null; } } @Override public Object getNativeCache() { try { return delegate.getNativeCache(); } catch (Exception e) { log.warn("redis异常,缓存功能失效..."); return null; } } @Override public Cache.ValueWrapper get(Object key) { try { return delegate.get(key); } catch (Exception e) { log.warn("redis异常,缓存功能失效..."); return null; } } @Override public <T> T get(Object o, Class<T> aClass) { try { return delegate.get(o, aClass); } catch (Exception e) { log.warn("@Cacheable异常,缓存功能失效..."); return null; } } @Override public <T> T get(Object o, Callable<T> callable) { try { return delegate.get(o, callable); } catch (Exception e) { try{ log.warn("@Cacheable异常,缓存功能失效..."); return callable.call(); } catch (Exception e1) { return null; } } } @Override public void put(Object key, Object value) { try { delegate.put(key, value); } catch (Exception e) { log.warn("@CachePut异常,缓存功能失效..."); } } @Override public ValueWrapper putIfAbsent(Object o, Object o1) { try { return delegate.putIfAbsent(o, o1); } catch (Exception e) { log.warn("@CachePut异常,缓存功能失效..."); return null; } } @Override public void evict(Object o) { try { delegate.evict(o); } catch (Exception e) { log.warn("@CacheEvict异常,缓存功能失效..."); } } @Override public void clear() { try { delegate.clear(); } catch (Exception e) { log.warn("redis异常,缓存功能失效..."); } } }
3、使用方式直接沿用spring cache
@Cacheable(key = "'OTN-'+#resID",value = "OTNCache",sync = true)
@CacheEvict(key = "'OTN-'+#resID",value = "OTNCache",beforeInvocation = true)
服务启动后,如何redis没有做缓存且宕机的话,通过RedisCacheWapper就能捕获redis的connection error错误
比如@Cacheable,
当宕机后调用
@Override public <T> T get(Object o, Callable<T> callable) { try { return delegate.get(o, callable); } catch (Exception e) { try{ log.warn("@Cacheable异常,缓存功能失效..."); return callable.call(); } catch (Exception e1) { return null; } } }
捕获redis连接异常,执行service层真实逻辑callable.call()