Paste_Image.png
在這里就不做spring框架詳細描述,只對用的作解釋,有什么問題歡迎來信。
1.pom添加
這里增加spring-data-redis
和jedis
必須要jar包。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.5.2</version>
</dependency>
2.spring 配置
在spring的配置文件applicationContext.xml里加入下面的redis的配置信息。
<!-- redis配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="300" />
<property name="maxTotal" value="600" />
<property name="maxWaitMillis" value="1000" />
<property name="testOnBorrow" value="true" />
</bean>
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="192.168.31.4" p:port="6379" p:password="" p:pool-config-ref="poolConfig"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
這里配置redis的一些信息,當然也可以用配置文件來配置
redis.host=192.168.31.4
redis.port=6379
redis.pass=
redis.maxIdle=50
redis.maxActive=50
redis.maxWait=50
redis.testOnBorrow=true
redis.timeout=1000
接下來在配置文件中配置要緩存的對象值,如下:
<cache:annotation-driven/>
<!-- 緩存管理器 -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="com.hejia.alauda.redis.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="default" />
<property name="timeout" value="600" /><!-- 10分鐘后過期 -->
</bean>
<bean class="com.hejia.alauda.redis.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="orderServiceImpl.selectInterests" />
<property name="timeout" value="600" />
</bean>
<bean class="com.hejia.alauda.redis.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="orderServiceImpl.selectInterestsList" />
<property name="timeout" value="600" />
</bean>
</set>
</property>
</bean>
這里面配置的orderServiceImpl.selectInterests 和 orderServiceImpl.selectInterestsList 分別是redis緩存的名稱,下面代碼會說到
3.redis緩存配置類
這里增加配置文件中實現(xiàn)的SystemRedisCache ,這里主要對redis的業(yè)務(wù)的操作方法。
import com.hejia.alauda.utils.SerializableUtil;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
/**
* info:redis緩存配置類
* Created by shang on 2016/11/9.
*/
public class SystemRedisCache implements Cache {
/**
* Redis
*/
private RedisTemplate<String, Object> redisTemplate;
/**
* 緩存名稱
*/
private String name;
/**
* 超時時間
*/
private long timeout;
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#getName()
*/
@Override
public String getName() {
return this.name;
}
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#getNativeCache()
*/
@Override
public Object getNativeCache() {
// TODO Auto-generated method stub
return this.redisTemplate;
}
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#get(java.lang.Object)
*/
@Override
public ValueWrapper get(Object key) {
if (StringUtils.isEmpty(key)) {
return null;
} else {
final String finalKey;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = key.toString();
}
Object object = null;
object = redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = finalKey.getBytes();
byte[] value = connection.get(key);
if (value == null) {
return null;
}
return SerializableUtil.unserialize(value);
}
});
return (object != null ? new SimpleValueWrapper(object) : null);
}
}
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#get(java.lang.Object, java.lang.Class)
*/
@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Class<T> type) {
if (StringUtils.isEmpty(key) || null == type) {
return null;
} else {
final String finalKey;
final Class<T> finalType = type;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = key.toString();
}
final Object object = redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = finalKey.getBytes();
byte[] value = connection.get(key);
if (value == null) {
return null;
}
return SerializableUtil.unserialize(value);
}
});
if (finalType != null && finalType.isInstance(object) && null != object) {
return (T) object;
} else {
return null;
}
}
}
/*
* (non-Javadoc)
* @see org.springframework.cache.Cache#put(java.lang.Object, java.lang.Object)
*/
@Override
public void put(final Object key, final Object value) {
if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return;
} else {
final String finalKey;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = key.toString();
}
if (!StringUtils.isEmpty(finalKey)) {
final Object finalValue = value;
redisTemplate.execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) {
connection.set(finalKey.getBytes(), SerializableUtil.serialize(finalValue));
// 設(shè)置超時間
connection.expire(finalKey.getBytes(), timeout);
return true;
}
});
}
}
}
/*
* 根據(jù)Key 刪除緩存
*/
@Override
public void evict(Object key) {
if (null != key) {
final String finalKey;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = key.toString();
}
if (!StringUtils.isEmpty(finalKey)) {
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.del(finalKey.getBytes());
}
});
}
}
}
/*
* 清楚系統(tǒng)緩存
*/
@Override
public void clear() {
// TODO Auto-generated method stub
// redisTemplate.execute(new RedisCallback<String>() {
// public String doInRedis(RedisConnection connection) throws DataAccessException {
// connection.flushDb();
// return "ok";
// }
// });
}
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void setName(String name) {
this.name = name;
}
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
this.timeout = timeout;
}
}
這里附帶一個工具類的代碼,主要對開發(fā)中object和list對象的序列化和反序列化。
因為redis不知object和泛型,所有在將對象存入redis時,需要將緩存的數(shù)據(jù)序列化。
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* info:序列化工具類
* Created by shang on 2016/11/9.
*/
public class SerializableUtil {
/**
* 序列化
*
* @param object
* @return
*/
public static byte[] serialize(Object object) {
if (object == null) {
return null;
}
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
byte[] bytes = null;
try {
// 序列化
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
bytes = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(oos);
close(baos);
}
return bytes;
}
/**
* 反序列化
*
* @param bytes
* @return
*/
public static Object unserialize(byte[] bytes) {
if (bytes == null) {
return null;
}
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(bais);
close(ois);
}
return null;
}
/**
* 序列化 list 集合
*
* @param list
* @return
*/
public static byte[] serializeList(List<?> list) {
if (list==null||list.size()==0) {
return null;
}
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
byte[] bytes = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
for (Object obj : list) {
oos.writeObject(obj);
}
bytes = baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
close(oos);
close(baos);
}
return bytes;
}
/**
* 反序列化 list 集合
*/
public static List<?> unserializeList(byte[] bytes) {
if (bytes == null) {
return null;
}
List<Object> list = new ArrayList<Object>();
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try {
// 反序列化
bais = new ByteArrayInputStream(bytes);
ois = new ObjectInputStream(bais);
while (bais.available() > 0) {
Object obj = (Object) ois.readObject();
if (obj == null) {
break;
}
list.add(obj);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close(bais);
close(ois);
}
return list;
}
/**
* 關(guān)閉io流對象
*
* @param closeable
*/
public static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4.緩存service方法
對指定的service方法做緩存,使用方法如下:
@Cacheable(value = "orderServiceImpl.selectInterests",key = "'selectInterests_'+#params.get('user_id')+'_'+#params.get('type')+'_'+#pager.pageNumber")//增加redis緩存
@Override
public Pager<Interest> selectInterests(Map<String, Object> params, Pager<Interest> pager) {
System.out.println("select selectInterests class ....");
pager.setList(interestMapper.findInterestListV3(params, pager));
pager.setTotalCount(interestMapper.findCountInterestListV3(params));
return pager;
}
@Cacheable(value = "orderServiceImpl.selectInterestsList",key = "'selectInterestsList_'+#params.get('user_id')+'_'+#params.get('type')+'_'+#params.get('valueDate')")//增加redis緩存
@Override
public List<Map<String, Object>> selectInterestsList(Map<String, Object> params) {
System.out.println("select ---selectInterestsList class");
return interestMapper.selectInterestsListV3(params);
}
這上面的兩個方法就是spring配置文件里配置的兩個緩存,我這里主要是對查詢的分頁做緩存。
上面的方法只是添加緩存,并10分鐘后過期。這里的key是在redis所對應(yīng)的標識,如果要查詢出來可以使用key值來查詢。
如果你需要對緩存進行修改和刪除,這需要使用@CachePut
和 @CacheEvict
。使用方法如下
Cache注解詳解
- @CacheConfig:主要用于配置該類中會用到的一些共用的緩存配置。在這里@CacheConfig(cacheNames = "users"):配置了該數(shù)據(jù)訪問對象中返回的內(nèi)容將存儲于名為users的緩存對象中,我們也可以不使用該注解,直接通過@Cacheable自己配置緩存集的名字來定義。
- @Cacheable:配置了findByName函數(shù)的返回值將被加入緩存。同時在查詢時,會先從緩存中獲取,若不存在才再發(fā)起對數(shù)據(jù)庫的訪問。該注解主要有下面幾個參數(shù):
- value、cacheNames:兩個等同的參數(shù)(cacheNames為Spring 4新增,作為value的別名),用于指定緩存存儲的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必須有的value屬性,也成為非必需項了
- key:緩存對象存儲在Map集合中的key值,非必需,缺省按照函數(shù)的所有參數(shù)組合作為key值,若自己配置需使用SpEL表達式,比如:@Cacheable(key = "#p0"):使用函數(shù)第一個參數(shù)作為緩存的key值,更多關(guān)于SpEL表達式的詳細內(nèi)容可參考官方文檔
- condition:緩存對象的條件,非必需,也需使用SpEL表達式,只有滿足表達式條件的內(nèi)容才會被緩存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有當?shù)谝粋€參數(shù)的長度小于3的時候才會被緩存,若做此配置上面的AAA用戶就不會被緩存,讀者可自行實驗嘗試。
- unless:另外一個緩存條件參數(shù),非必需,需使用SpEL表達式。它不同于condition參數(shù)的地方在于它的判斷時機,該條件是在函數(shù)被調(diào)用之后才做判斷的,所以它可以通過對result進行判斷。
- keyGenerator:用于指定key生成器,非必需。若需要指定一個自定義的key生成器,我們需要去實現(xiàn)org.springframework.cache.interceptor.KeyGenerator接口,并使用該參數(shù)來指定。需要注意的是:該參數(shù)與key是互斥的
- cacheManager:用于指定使用哪個緩存管理器,非必需。只有當有多個時才需要使用
- cacheResolver:用于指定使用那個緩存解析器,非必需。需通過org.springframework.cache.interceptor.CacheResolver接口來實現(xiàn)自己的緩存解析器,并用該參數(shù)指定。
除了這里用到的兩個注解之外,還有下面幾個核心注解:
- @CachePut:配置于函數(shù)上,能夠根據(jù)參數(shù)定義條件來進行緩存,它與@Cacheable不同的是,它每次都會真是調(diào)用函數(shù),所以主要用于數(shù)據(jù)新增和修改操作上。它的參數(shù)與@Cacheable類似,具體功能可參考上面對@Cacheable參數(shù)的解析
- @CacheEvict:配置于函數(shù)上,通常用在刪除方法上,用來從緩存中移除相應(yīng)數(shù)據(jù)。除了同@Cacheable一樣的參數(shù)之外,它還有下面兩個參數(shù):
- allEntries:非必需,默認為false。當為true時,會移除所有數(shù)據(jù)
- beforeInvocation:非必需,默認為false,會在調(diào)用方法之后移除數(shù)據(jù)。當為true時,會在調(diào)用方法之前移除數(shù)據(jù)。
5.結(jié)束
上面這些就是使用spring cache對redis做緩存的用法。如果在你的項目里需要可以試試一番,這里沒有使用Ecache緩存是因為項目使用分布式部署,如果是本地緩存就不行了,所以使用redis做緩存,統(tǒng)一存取。
有什么問題歡迎給我來信或留言!