spring cache redis
一、使用开源包(spring-data-redis)
1、引入jar包
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.11.RELEASE</version>
</dependency>
2、配置Spring xml文件
<!-- 结合现在配置 -->
<bean name="redisTemplate"
class=" RedisTemplate">
<property name="redisPool"
ref="redisPool"/>
<property name="keySerializer"
ref="org.springframework.data.redis.serializer.StringRedisSerializer"></property>
<property name="hashKeySerializer" ref="org.springframework.data.redis.serializer.StringRedisSerializer"></property>
</bean>
<bean name="cacheManager" class="com.config.ExtendedRedisCacheManager">
<constructor-arg name="redisOperations" ref="redisTemplate"/>
<constructor-arg name="cacheNames">
<set>
<value>default</value>
<value>test1</value>
</set>
</constructor-arg>
<!-- 默认缓存名字 -->
<property name="defaultCacheName" value="default"/>
<!-- 是否在容器启动时初始化 -->
<property name="loadRemoteCachesOnStartup" value="true"/>
<!-- 是否使用前缀 -->
<property name="usePrefix" value="true"/>
<!-- 前缀命名,仅当usePrefix为true时才生效
-->
<property name="cachePrefix">
<bean class="org.springframework.data.redis.cache.DefaultRedisCachePrefix">
<constructor-arg name="delimiter" value=":"/>
</bean>
</property>
<!-- 缓存名字和有效期的分隔符 -->
<property name="separator" value="#"/>
<!-- 默认有效期60 -->
<property name="defaultExpiration" value="60"/>
</bean>
ps:redis配置继续用现有的
3、配置redis挂掉,直接访问数据库(redis挂掉,最好配置预警)
@Configuration
@EnableCaching
public class AppCacheConfigurer extends CachingConfigurerSupport {
private Logger logger =
LoggerFactory.getLogger(AppCacheConfigurer.class);
public class AppCacheErrorHandler implements CacheErrorHandler {
@Override
public void handleCacheGetError(RuntimeException e,
Cache cache, Object o) {
if (e instanceof JedisConnectionException || e instanceof RedisConnectionFailureException) {
logger.warn("redis has lose connection:", e);
return;
}
throw e;
}
@Override
public void handleCachePutError(RuntimeException e,
Cache cache, Object o, Object o1) {
if (e instanceof JedisConnectionException || e instanceof RedisConnectionFailureException) {
logger.warn("redis has lose connection:", e);
return;
}
throw e;
}
@Override
public void handleCacheEvictError(RuntimeException
e, Cache cache, Object o) {
throw e;
}
@Override
public void handleCacheClearError(RuntimeException
e, Cache cache) {
throw e;
}
}
@Override
public CacheErrorHandler errorHandler() {
return new AppCacheErrorHandler();
}
}
5、配置独立设置过期时间,重写RedisCacheManager
public class ExtendedRedisCacheManager extends RedisCacheManager {
private static final Logger logger =
Logger.getLogger(ExtendedRedisCacheManager.class);
private static final ScriptEngine scriptEngine = new
ScriptEngineManager().getEngineByName("JavaScript");
private static final Pattern pattern = Pattern.compile("[+\\-*/%]");
private String defaultCacheName;
private char separator = '#';
public ExtendedRedisCacheManager(RedisOperations
redisOperations) {
this(redisOperations, Collections.<String>emptyList());
}
public ExtendedRedisCacheManager(RedisOperations
redisOperations, Collection<String> cacheNames) {
super(redisOperations, cacheNames);
}
@Override
public Cache getCache(String name) {
// try to get cache by name
RedisCache cache
= (RedisCache) super.getCache(name);
if (cache != null) {
return cache;
}
// there's no cache which has given name
// find separator in cache name
int index =
name.lastIndexOf(getSeparator());
if (index < 0) {
return null;
}
// split name by the separator
String cacheName
= name.substring(0, index);
if(StringUtils.isBlank(cacheName)){
cacheName = defaultCacheName;
}
cache = (RedisCache) super.getCache(cacheName);
if (cache == null) {
return null;
}
// get expiration from name
Long expiration
= getExpiration(name, index);
if (expiration == null || expiration < 0) {
logger.warn("Default expiration time will be used
for cache '{}' because cannot parse '{}', cacheName : " + cacheName + ", name : " + name);
return cache;
}
return new RedisCache(cacheName, (isUsePrefix() ?
getCachePrefix().prefix(cacheName) : null), getRedisOperations(), expiration);
}
public char getSeparator() {
return separator;
}
/**
* Char that separates cache name and
expiration time, default: #.
*
* @param separator
*/
public void setSeparator(char separator) {
this.separator = separator;
}
private Long getExpiration(final String name, final int separatorIndex) {
Long expiration = null;
String expirationAsString =
name.substring(separatorIndex + 1);
try {
// calculate expiration, support arithmetic
expressions.
if(pattern.matcher(expirationAsString).find()){
expiration = (long) Double.parseDouble(scriptEngine.eval(expirationAsString).toString());
}else{
expiration =
Long.parseLong(expirationAsString);
}
} catch (NumberFormatException ex) {
logger.error(String.format("Cannnot separate expiration time
from cache: '%s'",
name), ex);
} catch (ScriptException e) {
logger.error(String.format("Cannnot separate expiration time
from cache: '%s'",
name), e);
}
return expiration;
}
@Override
public void setUsePrefix(boolean usePrefix) {
super.setUsePrefix(usePrefix);
}
@Override
public void setCachePrefix(RedisCachePrefix
cachePrefix) {
super.setCachePrefix(cachePrefix);
}
public void setDefaultCacheName(String
defaultCacheName) {
this.defaultCacheName
= defaultCacheName;
}
}
6、通过注解设置缓存
@Cacheable(value = "test1#60",key = "#p0")//Cacheable会判断key是否存在,增加redis缓存,设置为60秒,key为test1:xxx
@CachePut(cacheNames="test1#60",key
= "#p0")//CachePut不会判断key是否存在,直接覆盖,增加redis缓存,设置为60秒,key为test1:xxx,它每次都会触发真实方法的调用
@CacheEvict(value = "test1",key = "#p1")//删除缓存
其他缓存注解,参考spring cache注解相关定义
二、解决现有系统版本不兼容问题
1、线上spring版本为:3.2.9.RELEASE
解决兼容redis挂掉的spring版本为4.1以上
适用于现在系统的配置如下
2、引入jar包
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
PS:低版本主要为了兼容现在的spring版本和jedis版本
3、实现自己的Spring cache,主要是为了兼容现有redis配置(现有系统redis的实现是自己实现的)
public class ExtendRedisCache implements Cache {
private static final Logger LOG = LoggerFactory.getLogger(ExtendRedisCache.class);
/**
* Redis
*/
private RedisTemplate redisTemplate;
/**
* 缓存名称
*/
private
String name;
/**
* 默认超时时间
*/
private
int timeout;
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return this.redisTemplate;
}
@Override
public ValueWrapper get(Object key) {
if (StringUtils.isEmpty(key)) {
return null;
}
Jedis jedis = null;
try{
jedis = redisTemplate.getRedisPool().getResource();
//键
final String finalKey = getKey(key);
if(StringUtils.isEmpty(finalKey)){
return null;
}
byte[] value = jedis.get(finalKey.getBytes());
if (value == null) {
return null;
}
Object object = SerializableUtil.unserialize(value);
return (object != null ? new SimpleValueWrapper(object) : null);
}catch (Exception e){
LOG.error("redis has lose connection:",e);
return null;
}finally {
if (null != jedis) {
jedis.close();
}
}
}
/**
* 获取redis缓存键
*
* @param key
* @return
*/
private String getKey(Object key) {
//键
final String finalKey;
if (key instanceof String) {
finalKey = this.name + ":" + (String) key;
} else {
finalKey = this.name + ":" + key.toString();
}
return finalKey;
}
@Override
public void put(Object key, Object value) {
if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return;
}
Jedis jedis = null;
try{
//键
final String finalKey = getKey(key);
if(!StringUtils.isEmpty(finalKey)){
jedis = redisTemplate.getRedisPool().getResource();
redisTemplate.set(finalKey.getBytes(),
SerializableUtil.serialize(value));
jedis.expire(finalKey.getBytes(),timeout);
}
}catch (Exception e){
LOG.error("redis has lose connection:",e);
}finally {
if (null != jedis) {
jedis.close();
}
}
}
/*
* 根据Key 删除缓存
*/
@Override
public void evict(Object key) {
if (null != key) {
try{
final String finalKey = getKey(key);
if (!StringUtils.isEmpty(finalKey)) {
redisTemplate.del(finalKey.getBytes());
}
}catch (Exception e){
LOG.error("redis has lose connection:",e);
}
}
}
/*
* 清除系统缓存
*/
@Override
public void clear() {
//线上不允许删除所有缓存
}
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate
redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void setName(String name) {
this.name = name;
}
public int getTimeout() {
return timeout;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
}
4、添加spring xml配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd ">
PS:添加红色标注地方
<!-- 启用Spring对基于注解的Cache的支持 -->
<cache:annotation-driven/>
<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="ExtendRedisCache">
<property name="redisTemplate" ref="redisTemplate" /> //现有系统的redisTemplate
<property name="name" value="test1" /> //缓存名(结合key)
<property name="timeout" value="60" /> //过期时间
</bean>
</set>
</property>
</bean>
5、通过注解设置缓存
@Cacheable(value = "test1",key = "#p0")//Cacheable会判断key是否存在,增加redis缓存,key为test1:xxx,这里过期时间在xml里配置
@CachePut(cacheNames="test1",key
= "#p0")//CachePut不会判断key是否存在,直接覆盖,它每次都会触发真实方法的调用,增加redis缓存,key为test1:xxx,,这里过期时间在xml里配置
@CacheEvict(value = "test1",key = "#p1")//删除缓存
其他缓存注解,参考spring cache注解相关定义
spring cache redis的更多相关文章
- spring Cache /Redis 缓存 + Spring 的集成示例
spring Cache https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/ spring+redis 缓存 ht ...
- Spring Cache Redis结合遇到的坑
业务上需要把一些数据放到redis里面,但是系统逻辑代码差不多编写完成了,怎么整?用Spring Cache啊,对既有业务逻辑侵袭极小. 于是尝试调查了一下,遇到一些问题分享一下(本文使用Spring ...
- 【快学SpringBoot】Spring Cache+Redis实现高可用缓存解决方案
前言 之前已经写过一篇文章介绍SpringBoot整合Spring Cache,SpringBoot默认使用的是ConcurrentMapCacheManager,在实际项目中,我们需要一个高可用的. ...
- 使用Spring Cache + Redis + Jackson Serializer缓存数据库查询结果中序列化问题的解决
应用场景 我们希望通过缓存来减少对关系型数据库的查询次数,减轻数据库压力.在执行DAO类的select***(), query***()方法时,先从Redis中查询有没有缓存数据,如果有则直接从Red ...
- spring Cache + Redis 开发数据字典以及自定义标签
一.数据库表结构 1. 分类表:dict_type 2. 子项表:dict_entry 二.页面维护功能示意图: 1. 分类管理 点击子项管理进入子项管理页面 2.子项管理 三.数据字典添加到缓 ...
- Spring Cache扩展:注解失效时间+主动刷新缓存
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- Spring Cache For Redis
一.概述 缓存(Caching)可以存储经常会用到的信息,这样每次需要的时候,这些信息都是立即可用的. 常用的缓存数据库: Redis 使用内存存储(in-memory)的非关系数据库,字符串.列 ...
- Spring Boot Cache Redis缓存
1.集成MyBatis 1.1.引入maven依赖 1.2.生成Mapper 具体可以看MyBatis Generator官网 http://www.mybatis.org/generator/run ...
- 【Spring】17、spring cache 与redis缓存整合
spring cache,基本能够满足一般应用对缓存的需求,但现实总是很复杂,当你的用户量上去或者性能跟不上,总需要进行扩展,这个时候你或许对其提供的内存缓存不满意了,因为其不支持高可用性,也不具备持 ...
随机推荐
- hibernate Day2 笔记
1.主键生成策略 <!--映射配置文件 >映射配置文件名称和位置没法有固定要求 >映射配置文件中的name属性值写实体类相关内容 -- class 标签name属性值实体类全路径 - ...
- Xenu使用随记
经试验发现,如果配置了host进行网站检测时,Xenu和浏览器一样,都需要配置了host之后,重新打开Xenu程序(浏览器),host的配置才能生效.
- win10安装CAD后出现致命错误
现在很多朋友在使用win10系统了,在win10系统打开cad却提示致命错误,这个时候应该怎么办呢?我们可以打开注册表编辑器然后找到某个注册表把数值改为0就可以解决这个问题了哦,下面就和小编一起来看看 ...
- ssm(Spring、Springmvc、Mybatis)实战之淘淘商城-第七天(非原创)
文章大纲 一.课程介绍二.Redis基础实战三.Redis之高可用.集群.云平台搭建实战四.淘淘商城Jedis整合spring五.项目源码与资料下载六.参考文章 一.课程介绍 一共14天课程(1) ...
- [原创] SOAP UI 创建SOAP工程进行接口测试
下载及安装 1. 登录http://www.soapui.org/ 2. 鼠标移动到导航头的Downloads选项 3. 点击SOAP UI 4. 下载页面 新建项目 创建项目 1. 创建项目很简单. ...
- SQL简单查询后续记录
--首先创建数据库TEST CREATE DATABASE TEST --创建表tb_user USE TEST CREATE TABLE [tb_user]( [name] [nvarchar] ( ...
- POJ 3107 Godfather (树的重心)
题意:求树的重心,若有多个,全部打印出来. 思路: 树的重心:在删除点v后,森林中的每棵树的节点数尽量均匀,若最大的那棵树的节点数最小,称v为树的重心. 这道题只是求树的所有重心,当且经当这棵树有对称 ...
- codevs 1131 统计单词数 2011年NOIP全国联赛普及组
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位 ...
- (二)SpringMVC之执行的过程
(DispatcherServlet在Spring当中充当一个前端控制器的角色,它的核心功能是分发请求.请求会被分发给对应处理的Java类,Spring MVC中称为Handle.) ① 用户把请 ...
- leetcode 4.两个排序数组的中位数
题目: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 . 请找出这两个有序数组的中位数.要求算法的时间复杂度为 O(log (m+n)) . 你可以假设 nums1 和 nums ...