spring cache,基本能够满足一般应用对缓存的需求,但现实总是很复杂,当你的用户量上去或者性能跟不上,总需要进行扩展,这个时候你或许对其提供的内存缓存不满意了,因为其不支持高可用性,也不具备持久化数据能力,这个时候,你就需要自定义你的缓存方案了,还好,spring 也想到了这一点。
本篇文章采用spring cache与redis进行整合,实现自己想要的缓存。
我们先配置redis:
第一步,要安装redis,这个自行百度,我们主要是配置redis。
增加一个redis配置文件,可以放在跟目录下
=192.168.0.43
=6379
=2015
=50
=50
=50
=true
=1000
还需要在spring的配置文件中去配置redis
<context:property-placeholder location="classpath:conf/" />
<bean class="">
<property name="maxIdle" value="${}" />
<property name="maxTotal" value="${}" />
<property name="maxWaitMillis" value="${}" />
<property name="testOnBorrow" value="${}" />
</bean>
<bean
class="">
<property name="poolConfig" ref="poolConfig" />
<property name="port" value="${}" />
<property name="hostName" value="${}" />
<property name="password" value="${}" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="connectionFactory" ref="connectionFactory" />
</bean>
好了,配置redis完成了。
现在我们来配置spring的cache:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
xmlns:xsi="http:///2001/XMLSchema-instance" xmlns:cache="/schema/cache"
xmlns:p="/schema/p"
xsi:schemaLocation="/schema/beans
/schema/beans/
/schema/cache
/schema/cache/">
<cache:annotation-driven />
<!-- 缓存管理器 -->
<bean class="">
<property name="caches">
<set>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="default" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name"
value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name"
value="" />
<property name="timeout" value="${}" />
</bean>
<bean class="">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name"
value="" />
<property name="timeout" value="${}" />
</bean>
</set>
</property>
<!-- <property name="fallbackToNoOpCache" value="false"/> -->
</bean>
</beans>
其实上面的配置文件,已经把redis与spring注解缓存的关系配置到了spring的xml文件中了。
对应的SystemRedisCache类是一个实现cache接口的自定义的缓存实现类。
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/**
* 〈一句话功能简述〉<br>
* 〈功能详细描述〉
*
* @author Administrator
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class SystemRedisCache implements Cache {
/**
* Redis
*/
private RedisTemplate<String, Object> redisTemplate;
/**
* 缓存名称
*/
private String name;
/**
* 超时时间
*/
private long timeout;
/*
* (non-Javadoc)
* @see #getName()
*/
@Override
public String getName() {
return ;
}
/*
* (non-Javadoc)
* @see #getNativeCache()
*/
@Override
public Object getNativeCache() {
// TODO Auto-generated method stub
return ;
}
/*
* (non-Javadoc)
* @see #get()
*/
@Override
public ValueWrapper get(Object key) {
if ((key)) {
return null;
} else {
final String finalKey;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = ();
}
Object object = null;
object = (new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = ();
byte[] value = (key);
if (value == null) {
return null;
}
return (value);
}
});
return (object != null ? new SimpleValueWrapper(object) : null);
}
}
/*
* (non-Javadoc)
* @see #get(, )
*/
@SuppressWarnings("unchecked")
@Override
public <T> T get(Object key, Class<T> type) {
if ((key) || null == type) {
return null;
} else {
final String finalKey;
final Class<T> finalType = type;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = ();
}
final Object object = (new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) throws DataAccessException {
byte[] key = ();
byte[] value = (key);
if (value == null) {
return null;
}
return (value);
}
});
if (finalType != null && (object) && null != object) {
return (T) object;
} else {
return null;
}
}
}
/*
* (non-Javadoc)
* @see #put(, )
*/
@Override
public void put(final Object key, final Object value) {
if ((key) || (value)) {
return;
} else {
final String finalKey;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = ();
}
if (!(finalKey)) {
final Object finalValue = value;
(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) {
((), (finalValue));
// 设置超时间
((), timeout);
return true;
}
});
}
}
}
/*
* 根据Key 删除缓存
*/
@Override
public void evict(Object key) {
if (null != key) {
final String finalKey;
if (key instanceof String) {
finalKey = (String) key;
} else {
finalKey = ();
}
if (!(finalKey)) {
(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return (());
}
});
}
}
}
/*
* 清楚系统缓存
*/
@Override
public void clear() {
// TODO Auto-generated method stub
// (new RedisCallback<String>() {
// public String doInRedis(RedisConnection connection) throws DataAccessException {
// ();
// return "ok";
// }
// });
}
public RedisTemplate<String, Object> getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
= redisTemplate;
}
public void setName(String name) {
= name;
}
public long getTimeout() {
return timeout;
}
public void setTimeout(long timeout) {
= timeout;
}
}
主要的方法就是get和put方法,里面的逻辑都是根据我们自己的需求去实现的。
现在有个问题,我们发现,在spring配置自己的注解缓存的配置文件中配置了多个cache,那spring是怎么去找到对应的cacheManager呢?
我们直接以代码给大家呈现出来:
/**
*
* 公共接口
*
* @author Administrator
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
@Service("commonService")
public class CommonServiceImpl implements CommonService {
/**
* 日志记录器
*/
private static final Logger LOGGER = ();
@Autowired
private DalClient dalClient;
/*
* @Autowired RedisTemplate<?, ?> redisTemplate;
*/
/**
* 根据名称获取自增序列squence的当前值
*
* @param SequenceName 自增序列名称
* @return 自增序列当前值
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
public String getSequenceByName(String SequenceName) {
if ((SequenceName)) {
("自增序列名称为空,无法返回正常的自增序列值");
return null;
} else {
Map<String, String> paramMap = new HashMap<String, String>();
("sequenceName", SequenceName);
// 查询sequence当前值
Map<String, Object> resultMap = ("common.GET_SEQUENCE_BY_NAME", paramMap);
if (null != resultMap && !()) {
return (("sequenceValue"));
} else {
return null;
}
}
}
/**
* 根据上一级的城市编码 查询 所有下属城市 列表
*
* @param parentCityCode
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#()", condition = "null != #parentCityCode")
public List<CityBean> queryCityListByParentCode(final Integer parentCityCode) {
Map<String, Object> paramMap = new HashMap<String, Object>();
if (null != parentCityCode) {
// 根据所选省份 \ 城市 查询所属城市列表
("parentCityCode", parentCityCode);
final List<CityBean> cityListResult = ("T_CITY.SELECT_BY_PARENTCODE", paramMap,
);
return cityListResult;
} else {
final List<CityBean> provinceListResult = ("T_CITY.SELECT_ALL_FIRST_STEP_CITY",
paramMap, );
return provinceListResult;
}
}
/**
* 根据上一级的行业编码 查询 所有下属所有行业
*
* @param parentCityCode
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#", condition = "null != #parentIndustryCode")
public List<IndustryBean> queryIndustryListByParentCode(final Integer parentIndustryCode) {
Map<String, Object> paramMap = new HashMap<String, Object>();
if (null != parentIndustryCode) {
("parentIndustryCode", parentIndustryCode);
final List<IndustryBean> industryListResult = ("T_INDUSTRY.SELECT_BY_PARENTCODE",
paramMap, );
return industryListResult;
} else {
final List<IndustryBean> industryListResult = (
"T_INDUSTRY.SELECT_ALL_FIRST_STEP_INDUSTRY", paramMap, );
return industryListResult;
}
}
/**
* 根据行业编码查询 行业信息
*
* @param industryCode
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#industryCode", condition = "(null != #industryCode) and (#() > 0)")
public IndustryBean queryIndustryInfoById(final String industryCode) {
if ((industryCode)) {
return null;
} else {
Map<String, Object> paramMap = new HashMap<String, Object>();
("industryCode", industryCode);
final IndustryBean industryInfoResult = ("T_INDUSTRY.SELECT_BY_ID", paramMap,
);
return industryInfoResult;
}
}
/**
* 递归删除 元素 因为可能存在重复的
*
* @param list 列表
* @param item 要删除的元素
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
private void deleteListElement(ArrayList<String> list, String item) {
if (null != list && !() && (item)) {
if ((item)) {
(item);
if ((item)) {
deleteListElement(list, item);
}
}
}
}
/**
* 根据行业id查询 行业名称
*
* @param industryIds 行业Id可能有多个 以分号分隔
* @return 行业名称列表
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#industryIds", condition = "null != #industryIds and #() > 0")
public List<String> queryIndustryNameByIds(final String industryIds) {
if ((industryIds)) {
return null;
} else {
String[] industryIdArr = (";");
if (null != industryIdArr && > 0) {
ArrayList<String> paramList = new ArrayList<String>();
((industryIdArr));
if (null != paramList && !()) {
Map<String, Object> paramMap = new HashMap<String, Object>();
("industryIdList", paramList);
// 查询行业列表
List<IndustryBean> queryResultList = ("T_INDUSTRY.SELECT_BY_ID_LIST",
paramMap, );
// 封装查询结果
List<String> industryNameList = new ArrayList<String>();
if (null != queryResultList && !()) {
// 遍历查询列表 将已经存在的编码去掉 剩下的 就是 根據编码查询不出行业的 直接将行业的名字返回
String tempId;
for (IndustryBean industryInfo : queryResultList) {
if (null != industryInfo) {
if (null == ()) {
continue;
} else {
tempId = ().toString();
if ((tempId)) {
deleteListElement(paramList, tempId);
}
if ((())) {
(());
}
}
}
}
}
// 将根据编码查询不出来 的 行业编码 直接返回
(paramList);
return industryNameList;
}
}
return null;
}
}
/**
* 根据城市id查询 城市名称
*
* @param industryIds 行业Id可能有多个 以分号分隔
* @return 行业名称列表
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#cityIds", condition = "null != #cityIds and #() > 0")
public List<String> queryCityNameByIds(String cityIds) {
if ((cityIds)) {
return null;
} else {
String replacyedCityIds = (";", ",");
String[] industryIdArr = (",");
if (null != industryIdArr && > 0) {
ArrayList<String> paramList = new ArrayList<String>();
((industryIdArr));
if (null != paramList && !()) {
Map<String, Object> paramMap = new HashMap<String, Object>();
("cityIdList", paramList);
// 查询行业列表
List<CityBean> queryResultList = ("T_CITY.SELECT_BY_ID_LIST", paramMap,
);
List<String> industryNameList = new ArrayList<String>();
if (null != queryResultList && !()) {
// 遍历查询列表 将已经存在的编码去掉 剩下的 就是 根據编码查询不出行业的 直接将行业的名字返回
// 封装查询结果
String tempId;
for (CityBean industryInfo : queryResultList) {
if (null != industryInfo) {
if (null == ()) {
continue;
} else {
tempId = ().toString();
if ((tempId)) {
deleteListElement(paramList, tempId);
}
if ((())) {
(());
}
}
}
}
}
// 将根据编码查询不出来 的 行业编码 直接返回
(paramList);
return industryNameList;
}
}
return null;
}
}
/**
* 查询第一级所有职位
*
* @return
*/
@Override
public List<JobTypeVo> queryFirstJobList() {
/*
* List<JobTypeVo> redisIndustryListResult = (new RedisCallback<List<JobTypeVo>>() {
* @Override public List<JobTypeVo> doInRedis(RedisConnection connection) { byte[] industryListList =
* ((RedisConstants.JOB_FIRST_LIST).getBytes()); if (null != industryListList &&
* > 0) { return (List<JobTypeVo>) (industryListList);
* } else { return null; } } }); if (null != redisIndustryListResult && !()) {
* return redisIndustryListResult; } else {
*/
final List<JobTypeVo> queryIndustryListResult = ("T_JOB_TYPE.SELECT_FIRST_JOB_CODE",
null, );
/*
* if (null != queryIndustryListResult && !()) { (new
* RedisCallback<Boolean>() {
* @Override public Boolean doInRedis(RedisConnection connection) {
* ((RedisConstants.JOB_FIRST_LIST).getBytes(),
* (queryIndustryListResult)); return true; } }); }
*/
return queryIndustryListResult;
/* } */
}
/**
* 查询 对应级别的职位信息
*
* @param typeValue
* @param jobCode
* @return
*/
@Override
public List<JobTypeBean> queryJobTypeList(final int typeValue, final int jobCode) {
/*
* List<JobTypeBean> redisIndustryListResult = (new RedisCallback<List<JobTypeBean>>() {
* @Override public List<JobTypeBean> doInRedis(RedisConnection connection) { byte[] industryListList =
* ((RedisConstants.JOB_FIRST_LIST + typeValue + jobCode) .getBytes()); if (null !=
* industryListList && > 0) { return (List<JobTypeBean>)
* (industryListList); } else { return null; } } }); if (null !=
* redisIndustryListResult && !()) { return redisIndustryListResult; } else {
*/
Map<String, Object> paramMap = new HashMap<String, Object>();
("typeValue", typeValue);
("jobFirstCode", jobCode);
final List<JobTypeBean> queryResult = ("T_JOB_TYPE.SELECT_BY_JOB_CODE", paramMap,
);
/*
* if (null != queryResult && !()) { (new RedisCallback<Boolean>() {
* @Override public Boolean doInRedis(RedisConnection connection) {
* ((RedisConstants.JOB_FIRST_LIST + typeValue + jobCode).getBytes(),
* (queryResult)); return true; } }); }
*/
return queryResult;
/* } */
}
/**
* 判断学校是否 特殊学校
*
* @param schoolName 学校名称
* @param schoolType 学校分类(1:211 暂无其他)
* @return true:是, false:否
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#schoolName + #schoolType", condition = "null != #schoolName and null !=#schoolType and #() > 0")
public boolean isSpecialSchool(String schoolName, int schoolType) {
if ((schoolName)) {
return false;
} else {
Map<String, Object> paramMap = new HashMap<String, Object>();
("schoolName", schoolName);
("schoolType", schoolType);
Map<String, Object> resultMap = ("T_MY_SPECIAL_SCHOOL.SELECT_BY_NAME_TYPE", paramMap);
if (null != resultMap && !() && ("NUM")) {
return (long) ("NUM") > 0;
} else {
return false;
}
}
}
/**
* 根据城市名称获取 城市所在 省份名称
*
* @param cityNames
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "", key = "new String('')+#cityNames", condition = "null != #cityNames and #() > 0")
public String getProvinceByCity(final String cityNames) {
if ((cityNames)) {
return null;
} else {
String[] cityArr = ("、");
Map<String, Object> paramMap = new HashMap<String, Object>();
Map<String, Object> resultMap;
String provinceName;
List<String> provinceLait = new ArrayList<String>();
for (String cityName : cityArr) {
if ((cityName)) {
("cityName", cityName);
resultMap = ("T_CITY.SELECT_PROVINCE_NAMEBY_CITY_NAME", paramMap);
if (null != resultMap && !() && ("provinceName")) {
provinceName = (("provinceName"));
if (!(provinceName)) {
(provinceName);
}
}
}
}
StringBuffer sb = new StringBuffer(100);
if (!()) {
for (int i = 0; i < (); i++) {
if (i < () - 1) {
((i)).append(",");
} else {
((i));
}
}
}
return ();
}
}
已queryCityListByParentCode方法为例:
在这个方法上面有@Cacheable这个注解,这个是spring3.1以后增加的注解缓存标签,它会根据value = ""中value的属性值去查找我们配置在spring的xml文件中的name属性去查找,找到对应的配置文件后,该方法会通过我们自定义的缓存实现类去实现对应的逻辑,如果对spring注解的意义不清楚的可以先去了解下spring cache注解的含义。
好了,spring cache与redis的缓存整合就ok了