spring cache,基本能够满足一般应用对缓存的需求,但现实总是很复杂,当你的用户量上去或者性能跟不上,总需要进行扩展,这个时候你或许对其提供的内存缓存不满意了,因为其不支持高可用性,也不具备持久化数据能力,这个时候,你就需要自定义你的缓存方案了,还好,spring 也想到了这一点。

本篇文章采用spring cache与Redis进行整合,实现自己想要的缓存。

我们先配置redis:

第一步,要安装redis,这个自行百度,我们主要是配置redis。

增加一个redis配置文件,可以放在跟目录下

redis.host=192.168.0.43
redis.port=6379
redis.pass=2015
redis.maxIdle=50
redis.maxActive=50
redis.maxWait=50
redis.testOnBorrow=true
redis.timeout=1000

还需要在spring的配置文件中去配置redis

<context:property-placeholder location="classpath:conf/redis.properties" />

    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxWaitMillis" value="${redis.maxWait}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean> <bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="poolConfig" ref="poolConfig" />
<property name="port" value="${redis.port}" />
<property name="hostName" value="${redis.host}" />
<property name="password" value="${redis.pass}" />
<property name="timeout" value="${redis.timeout}" />
</bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="connectionFactory" />
</bean>

好了,配置redis完成了。

现在我们来配置spring的cache:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd"> <cache:annotation-driven /> <!-- 缓存管理器 -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="default" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="commonService.queryCityListByParentCode" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name"
value="commonService.queryIndustryListByParentCode" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="commonService.queryIndustryInfoById" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="commonService.queryIndustryNameByIds" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="commonService.queryCityNameByIds" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="commonService.isSpecialSchool" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="commonService.getProvinceByCity" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="permissionService.queryMenuList" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="permissionService.queryOperationOfMenu" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="roleService.queryAllRole" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name" value="permissionService.queryPermissionTree" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name"
value="permissionService.queryPermissaionMenuByRoleCode" />
<property name="timeout" value="${redis.timeout}" />
</bean>
<bean class="com.config.SystemRedisCache">
<property name="redisTemplate" ref="redisTemplate" />
<property name="name"
value="permissionService.queryAllPermissionByRoleCode" />
<property name="timeout" value="${redis.timeout}" />
</bean>
</set>
</property>
<!-- <property name="fallbackToNoOpCache" value="false"/> -->
</bean>
</beans>

其实上面的配置文件,已经把redis与spring注解缓存的关系配置到了spring的xml文件中了。

对应的SystemRedisCache类是一个实现cache接口的自定义的缓存实现类。

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; /**
* 〈一句话功能简述〉<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 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 SerializableObjectUtil.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 SerializableObjectUtil.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(), SerializableObjectUtil.serialize(finalValue));
// 设置超时间
connection.expire(finalKey.getBytes(), 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 = key.toString();
}
if (!StringUtils.isEmpty(finalKey)) {
redisTemplate.execute(new RedisCallback<Long>() {
public Long doInRedis(RedisConnection connection) throws DataAccessException {
return connection.del(finalKey.getBytes());
}
});
}
}
} /*
* 清楚系统缓存
*/
@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;
}
}

主要的方法就是get和put方法,里面的逻辑都是根据我们自己的需求去实现的。

现在有个问题,我们发现,在spring配置自己的注解缓存的配置文件中配置了多个cache,那spring是怎么去找到对应的cacheManager呢?

我们直接以代码给大家呈现出来:

/**
*
* 公共接口
*
* @author Administrator
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
@Service("commonService")
public class CommonServiceImpl implements CommonService { /**
* 日志记录器
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CommonServiceImpl.class); @Autowired
private DalClient dalClient; /*
* @Autowired RedisTemplate<?, ?> redisTemplate;
*/ /**
* 根据名称获取自增序列squence的当前值
*
* @param SequenceName 自增序列名称
* @return 自增序列当前值
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
public String getSequenceByName(String SequenceName) {
if (StringUtils.isEmpty(SequenceName)) {
LOGGER.error("自增序列名称为空,无法返回正常的自增序列值");
return null;
} else {
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("sequenceName", SequenceName);
// 查询sequence当前值
Map<String, Object> resultMap = dalClient.queryForMap("common.GET_SEQUENCE_BY_NAME", paramMap);
if (null != resultMap && !resultMap.isEmpty()) {
return String.valueOf(resultMap.get("sequenceValue"));
} else {
return null;
}
}
} /**
* 根据上一级的城市编码 查询 所有下属城市 列表
*
* @param parentCityCode
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.queryCityListByParentCode", key = "new String('commonService.queryCityListByParentCode')+#parentCityCode.toString()", condition = "null != #parentCityCode")
public List<CityBean> queryCityListByParentCode(final Integer parentCityCode) {
Map<String, Object> paramMap = new HashMap<String, Object>();
if (null != parentCityCode) {
// 根据所选省份 \ 城市 查询所属城市列表
paramMap.put("parentCityCode", parentCityCode); final List<CityBean> cityListResult = dalClient.queryForList("T_CITY.SELECT_BY_PARENTCODE", paramMap,
CityBean.class);
return cityListResult;
} else {
final List<CityBean> provinceListResult = dalClient.queryForList("T_CITY.SELECT_ALL_FIRST_STEP_CITY",
paramMap, CityBean.class);
return provinceListResult;
}
} /**
* 根据上一级的行业编码 查询 所有下属所有行业
*
* @param parentCityCode
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.queryIndustryListByParentCode", key = "new String('commonService.queryIndustryListByParentCode')+#parentIndustryCode.toString", condition = "null != #parentIndustryCode")
public List<IndustryBean> queryIndustryListByParentCode(final Integer parentIndustryCode) {
Map<String, Object> paramMap = new HashMap<String, Object>();
if (null != parentIndustryCode) {
paramMap.put("parentIndustryCode", parentIndustryCode);
final List<IndustryBean> industryListResult = dalClient.queryForList("T_INDUSTRY.SELECT_BY_PARENTCODE",
paramMap, IndustryBean.class);
return industryListResult;
} else {
final List<IndustryBean> industryListResult = dalClient.queryForList(
"T_INDUSTRY.SELECT_ALL_FIRST_STEP_INDUSTRY", paramMap, IndustryBean.class);
return industryListResult;
}
} /**
* 根据行业编码查询 行业信息
*
* @param industryCode
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.queryIndustryInfoById", key = "new String('commonService.queryIndustryInfoById')+#industryCode", condition = "(null != #industryCode) and (#industryCode.length() > 0)")
public IndustryBean queryIndustryInfoById(final String industryCode) {
if (StringUtils.isEmpty(industryCode)) {
return null;
} else {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("industryCode", industryCode);
final IndustryBean industryInfoResult = dalClient.queryForObject("T_INDUSTRY.SELECT_BY_ID", paramMap,
IndustryBean.class);
return industryInfoResult;
}
} /**
* 递归删除 元素 因为可能存在重复的
*
* @param list 列表
* @param item 要删除的元素
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
private void deleteListElement(ArrayList<String> list, String item) {
if (null != list && !list.isEmpty() && StringUtils.isNotBlank(item)) {
if (list.contains(item)) {
list.remove(item);
if (list.contains(item)) {
deleteListElement(list, item);
}
}
}
} /**
* 根据行业id查询 行业名称
*
* @param industryIds 行业Id可能有多个 以分号分隔
* @return 行业名称列表
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.queryIndustryNameByIds", key = "new String('commonService.queryIndustryNameByIds')+#industryIds", condition = "null != #industryIds and #industryIds.length() > 0")
public List<String> queryIndustryNameByIds(final String industryIds) {
if (StringUtils.isBlank(industryIds)) {
return null;
} else {
String[] industryIdArr = industryIds.split(";");
if (null != industryIdArr && industryIdArr.length > 0) {
ArrayList<String> paramList = new ArrayList<String>();
paramList.addAll(Arrays.asList(industryIdArr));
if (null != paramList && !paramList.isEmpty()) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("industryIdList", paramList);
// 查询行业列表
List<IndustryBean> queryResultList = dalClient.queryForList("T_INDUSTRY.SELECT_BY_ID_LIST",
paramMap, IndustryBean.class);
// 封装查询结果
List<String> industryNameList = new ArrayList<String>();
if (null != queryResultList && !queryResultList.isEmpty()) {
// 遍历查询列表 将已经存在的编码去掉 剩下的 就是 根據编码查询不出行业的 直接将行业的名字返回
String tempId;
for (IndustryBean industryInfo : queryResultList) {
if (null != industryInfo) {
if (null == industryInfo.getIndustryCode()) {
continue;
} else {
tempId = industryInfo.getIndustryCode().toString();
if (paramList.contains(tempId)) {
deleteListElement(paramList, tempId);
}
if (StringUtils.isNotBlank(industryInfo.getIndustryName())) {
industryNameList.add(industryInfo.getIndustryName());
}
}
}
}
}
// 将根据编码查询不出来 的 行业编码 直接返回
industryNameList.addAll(paramList);
return industryNameList;
}
}
return null;
}
} /**
* 根据城市id查询 城市名称
*
* @param industryIds 行业Id可能有多个 以分号分隔
* @return 行业名称列表
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.queryCityNameByIds", key = "new String('commonService.queryCityNameByIds')+#cityIds", condition = "null != #cityIds and #cityIds.length() > 0")
public List<String> queryCityNameByIds(String cityIds) {
if (StringUtils.isBlank(cityIds)) {
return null;
} else {
String replacyedCityIds = cityIds.replace(";", ",");
String[] industryIdArr = replacyedCityIds.split(",");
if (null != industryIdArr && industryIdArr.length > 0) {
ArrayList<String> paramList = new ArrayList<String>();
paramList.addAll(Arrays.asList(industryIdArr));
if (null != paramList && !paramList.isEmpty()) {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("cityIdList", paramList);
// 查询行业列表
List<CityBean> queryResultList = dalClient.queryForList("T_CITY.SELECT_BY_ID_LIST", paramMap,
CityBean.class);
List<String> industryNameList = new ArrayList<String>();
if (null != queryResultList && !queryResultList.isEmpty()) {
// 遍历查询列表 将已经存在的编码去掉 剩下的 就是 根據编码查询不出行业的 直接将行业的名字返回
// 封装查询结果
String tempId;
for (CityBean industryInfo : queryResultList) {
if (null != industryInfo) {
if (null == industryInfo.getCityCode()) {
continue;
} else {
tempId = industryInfo.getCityCode().toString();
if (paramList.contains(tempId)) {
deleteListElement(paramList, tempId);
}
if (StringUtils.isNotBlank(industryInfo.getCityName())) {
industryNameList.add(industryInfo.getCityName());
}
}
}
}
}
// 将根据编码查询不出来 的 行业编码 直接返回
industryNameList.addAll(paramList);
return industryNameList;
}
}
return null;
}
} /**
* 查询第一级所有职位
*
* @return
*/
@Override
public List<JobTypeVo> queryFirstJobList() {
/*
* List<JobTypeVo> redisIndustryListResult = redisTemplate.execute(new RedisCallback<List<JobTypeVo>>() {
* @Override public List<JobTypeVo> doInRedis(RedisConnection connection) { byte[] industryListList =
* connection.get((RedisConstants.JOB_FIRST_LIST).getBytes()); if (null != industryListList &&
* industryListList.length > 0) { return (List<JobTypeVo>) SerializableObjectUtil.unserialize(industryListList);
* } else { return null; } } }); if (null != redisIndustryListResult && !redisIndustryListResult.isEmpty()) {
* return redisIndustryListResult; } else {
*/
final List<JobTypeVo> queryIndustryListResult = dalClient.queryForList("T_JOB_TYPE.SELECT_FIRST_JOB_CODE",
null, JobTypeVo.class);
/*
* if (null != queryIndustryListResult && !queryIndustryListResult.isEmpty()) { redisTemplate.execute(new
* RedisCallback<Boolean>() {
* @Override public Boolean doInRedis(RedisConnection connection) {
* connection.set((RedisConstants.JOB_FIRST_LIST).getBytes(),
* SerializableObjectUtil.serialize(queryIndustryListResult)); return true; } }); }
*/
return queryIndustryListResult;
/* } */
} /**
* 查询 对应级别的职位信息
*
* @param typeValue
* @param jobCode
* @return
*/
@Override
public List<JobTypeBean> queryJobTypeList(final int typeValue, final int jobCode) {
/*
* List<JobTypeBean> redisIndustryListResult = redisTemplate.execute(new RedisCallback<List<JobTypeBean>>() {
* @Override public List<JobTypeBean> doInRedis(RedisConnection connection) { byte[] industryListList =
* connection.get((RedisConstants.JOB_FIRST_LIST + typeValue + jobCode) .getBytes()); if (null !=
* industryListList && industryListList.length > 0) { return (List<JobTypeBean>)
* SerializableObjectUtil.unserialize(industryListList); } else { return null; } } }); if (null !=
* redisIndustryListResult && !redisIndustryListResult.isEmpty()) { return redisIndustryListResult; } else {
*/
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("typeValue", typeValue);
paramMap.put("jobFirstCode", jobCode);
final List<JobTypeBean> queryResult = dalClient.queryForList("T_JOB_TYPE.SELECT_BY_JOB_CODE", paramMap,
JobTypeBean.class);
/*
* if (null != queryResult && !queryResult.isEmpty()) { redisTemplate.execute(new RedisCallback<Boolean>() {
* @Override public Boolean doInRedis(RedisConnection connection) {
* connection.set((RedisConstants.JOB_FIRST_LIST + typeValue + jobCode).getBytes(),
* SerializableObjectUtil.serialize(queryResult)); return true; } }); }
*/
return queryResult;
/* } */
} /**
* 判断学校是否 特殊学校
*
* @param schoolName 学校名称
* @param schoolType 学校分类(1:211 暂无其他)
* @return true:是, false:否
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.isSpecialSchool", key = "new String('commonService.isSpecialSchool')+#schoolName + #schoolType", condition = "null != #schoolName and null !=#schoolType and #schoolName.length() > 0")
public boolean isSpecialSchool(String schoolName, int schoolType) {
if (StringUtils.isEmpty(schoolName)) {
return false;
} else {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("schoolName", schoolName);
paramMap.put("schoolType", schoolType);
Map<String, Object> resultMap = dalClient.queryForMap("T_MY_SPECIAL_SCHOOL.SELECT_BY_NAME_TYPE", paramMap);
if (null != resultMap && !resultMap.isEmpty() && resultMap.containsKey("NUM")) {
return (long) resultMap.get("NUM") > 0;
} else {
return false;
}
}
} /**
* 根据城市名称获取 城市所在 省份名称
*
* @param cityNames
* @return
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Override
@Cacheable(value = "commonService.getProvinceByCity", key = "new String('commonService.getProvinceByCity')+#cityNames", condition = "null != #cityNames and #cityNames.length() > 0")
public String getProvinceByCity(final String cityNames) {
if (StringUtils.isBlank(cityNames)) {
return null;
} else {
String[] cityArr = cityNames.split("、");
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 (StringUtils.isNotBlank(cityName)) {
paramMap.put("cityName", cityName);
resultMap = dalClient.queryForMap("T_CITY.SELECT_PROVINCE_NAMEBY_CITY_NAME", paramMap);
if (null != resultMap && !resultMap.isEmpty() && resultMap.containsKey("provinceName")) {
provinceName = String.valueOf(resultMap.get("provinceName"));
if (!provinceLait.contains(provinceName)) {
provinceLait.add(provinceName);
}
}
}
}
StringBuffer sb = new StringBuffer(100);
if (!provinceLait.isEmpty()) {
for (int i = 0; i < provinceLait.size(); i++) {
if (i < provinceLait.size() - 1) {
sb.append(provinceLait.get(i)).append(",");
} else {
sb.append(provinceLait.get(i));
}
}
}
return sb.toString();
}
}

已queryCityListByParentCode方法为例:

在这个方法上面有@Cacheable这个注解,这个是spring3.1以后增加的注解缓存标签,它会根据value = "commonService.queryCityListByParentCode"中value的属性值去查找我们配置在spring的xml文件中的name属性去查找,找到对应的配置文件后,该方法会通过我们自定义的缓存实现类去实现对应的逻辑,如果对spring注解的意义不清楚的可以先去了解下spring cache注解的含义。

友情链接:【Spring】22、Spring缓存注解@Cache使用

【Spring】17、spring cache 与redis缓存整合的更多相关文章

  1. springboot 用redis缓存整合spring cache注解,使用Json序列化和反序列化。

    springboot下用cache注解整合redis并使用json序列化反序列化. cache注解整合redis 最近发现spring的注解用起来真的是很方便.随即产生了能不能吧spring注解使用r ...

  2. spring boot 2.0.4 Redis缓存配置

    spring boot 2 使用RedisTemplate操作redis存取对象时,需要先进行序列化操作 import org.springframework.cache.CacheManager; ...

  3. 搞懂分布式技术14:Spring Boot使用注解集成Redis缓存

    本文内容参考网络,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutor ...

  4. 基于Spring接口,集成Caffeine+Redis两级缓存

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 在上一篇文章Redis+Caffeine两级缓存,让访问速度纵享丝滑中,我们介绍了3种整合Caffeine和Redis作为两级缓存使用的方法,虽 ...

  5. 【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)

    一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...

  6. 从零搭建Spring Boot脚手架(6):整合Redis作为缓存

    1. 前言 上一文我们整合了Mybatis Plus,今天我们会把缓存也集成进来.缓存是一个系统应用必备的一种功能,除了在减轻数据库的压力之外.还在存储一些短时效的数据场景中发挥着重大作用,比如存储用 ...

  7. spring整合redis缓存,以注解(@Cacheable、@CachePut、@CacheEvict)形式使用

    maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略: <dependency> <groupId>redis.clients</grou ...

  8. 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)

    如约而至,Java 10 正式发布!   3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...

  9. Spring优雅整合Redis缓存

    “小明,多系统的session共享,怎么处理?”“Redis缓存啊!” “小明,我想实现一个简单的消息队列?”“Redis缓存啊!” “小明,分布式锁这玩意有什么方案?”“Redis缓存啊!” “小明 ...

随机推荐

  1. WSGI and Paste学习笔记

    The Problem Lots of web frameworks Zope, Quixote, Webware, SkunkWeb and Twisted Web etc Applications ...

  2. 看CES 2017上有哪些好玩的物联网设备

    2017年国际消费类电子产品展览会(CES)已于昨天在拉斯维加斯正式开幕,多款新一代智能手机和平板电脑亮相本届CES大展,智能家居.穿戴等设备更成为外界普遍关注的焦点.今天笔者将带大家一览CES 20 ...

  3. SQL Server profile使用技巧

    200 ? "200px" : this.width)!important;} --> 介绍 经常会有人问profile工具该怎么使用?有没有方法获取性能差的sql的问题.自 ...

  4. HTML5之日历控件

    HTML5定义了几个与日期有关的新控件.支持日期控件的浏览器会提供一个方便的下拉式日历,供用户选择. 以下测试和截图都是在谷歌浏览器完成的,其他浏览器可能略有差异. 1.日期时间控件 HTML代码: ...

  5. Cocos2d-x环境配置步骤

    Cocos2d-x环境配置: (1)安装Visual Studio 2013 软件安装包为:VS2013_RTM_ULT_CHS.iso文件,将其解压后可以直接安装,也可以使用虚拟光驱等软件进行安装. ...

  6. 如何将一个文本内容通过PHP 以表格的方式输入到页面上

    如何将一个文本内容通过PHP 以表格的方式输入到页面上 <?php //读取文本内容 $contents = file_get_contents("names.txt"); ...

  7. thymeleaf-在font标签中的使用

    <font color="red" th:text="开始了">font外</font>页面显示红色字体 开始了 (同时存在,则前者覆盖 ...

  8. Asp.NetCoreWebApi图片上传接口(二)集成IdentityServer4授权访问(附源码)

    写在前面 本文地址:http://www.cnblogs.com/yilezhu/p/9315644.html 作者:yilezhu 上一篇关于Asp.Net Core Web Api图片上传的文章使 ...

  9. mysql 开发基础系列7 流程函数与其它函数

    一.流程函数 -- 创建表来介绍 ,)); ,),(,), (,),(,),(,), (,NULL); SELECT * FROM salary 1. if(value,t,f)  超过2000的用h ...

  10. 改变input的值不会触发change事件的解决思路

    通常来说,如果我们自己通过 value 改变了 input 元素的值,我们肯定是知道的,但是在某些场景下,页面上有别的逻辑在改变 input 的 value 值,我们可能希望能在这个值发生变化的时候收 ...