【Spring】17、spring cache 与redis缓存整合
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缓存整合的更多相关文章
- springboot 用redis缓存整合spring cache注解,使用Json序列化和反序列化。
springboot下用cache注解整合redis并使用json序列化反序列化. cache注解整合redis 最近发现spring的注解用起来真的是很方便.随即产生了能不能吧spring注解使用r ...
- spring boot 2.0.4 Redis缓存配置
spring boot 2 使用RedisTemplate操作redis存取对象时,需要先进行序列化操作 import org.springframework.cache.CacheManager; ...
- 搞懂分布式技术14:Spring Boot使用注解集成Redis缓存
本文内容参考网络,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutor ...
- 基于Spring接口,集成Caffeine+Redis两级缓存
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 在上一篇文章Redis+Caffeine两级缓存,让访问速度纵享丝滑中,我们介绍了3种整合Caffeine和Redis作为两级缓存使用的方法,虽 ...
- 【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)
一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...
- 从零搭建Spring Boot脚手架(6):整合Redis作为缓存
1. 前言 上一文我们整合了Mybatis Plus,今天我们会把缓存也集成进来.缓存是一个系统应用必备的一种功能,除了在减轻数据库的压力之外.还在存储一些短时效的数据场景中发挥着重大作用,比如存储用 ...
- spring整合redis缓存,以注解(@Cacheable、@CachePut、@CacheEvict)形式使用
maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略: <dependency> <groupId>redis.clients</grou ...
- 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)
如约而至,Java 10 正式发布! 3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...
- Spring优雅整合Redis缓存
“小明,多系统的session共享,怎么处理?”“Redis缓存啊!” “小明,我想实现一个简单的消息队列?”“Redis缓存啊!” “小明,分布式锁这玩意有什么方案?”“Redis缓存啊!” “小明 ...
随机推荐
- Linux基本命令-ls
ls 作用:显示目标列表,在Linux中是使用率较高的命令.ls命令的输出信息可以进行彩色加亮显示,以分区不同类型的文件. 参数: -a:显示所有档案及目录(ls内定将档案名或目录名称为“.”的视为影 ...
- Python psutil模块使用
import psutil # 获取内存信息 mem = psutil.virtual_memory() total = mem.total / 1024 / 1024 / 1024 used = m ...
- 吴恩达机器学习笔记44-核函数(Kernels)
回顾我们之前讨论过可以使用高级数的多项式模型来解决无法用直线进行分隔的分类问题: 为了获得上图所示的判定边界,我们的模型可能是
- 【app】adb连接问题整理
如果使用adb devices进行检测,发现没有任何设备信息,我们就需要检查是否有手机/模拟器连接上 如果是手机进行连接,windows右下角有出来如下提示的话,需要检查你的手机驱动是否有安装好 如果 ...
- Java多线程之二(Synchronized)
常用API method 注释 run() run()方法是我们创建线程时必须要实现的方法,但是实际上该方法只是一个普通方法,直接调用并没有开启线程的作用. start() start()方法作用为使 ...
- ⑧javaWeb之在例子中学习(过滤器Filter)
前言 本系列 Servlet & JSP 学习系列[传送门]逐渐到了中期了,希望大家喜欢我写的,总结的点点滴滴- 今天我们来讲讲过滤器 你们的支持是我写博客的动力哦. 最近买了两本书,觉得大二 ...
- XML技术思想
百科名片: 可扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语 ...
- MySQL 锁信息和事务
1 锁概念 1.1 什么是锁 锁是数据库系统区别于文件系统的一个关键特性.数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性.例如:操作缓冲池中的LRU列表,删除.添加.移动L ...
- git版本管理规范
一.基本开发流程: 二.分支命名 2.1主分支 ① master :随时可供在生产环境中部署的代码 ② dev: 保存当前稳定并且最新的开发分支(多人开发同一分支) 2.2辅助分支 主要用于新功能的并 ...
- MFC原理第二讲.MFC的初始化过程
MFC原理第二讲MFC的初始化过程 一丶简介 通过上一讲.我们手工模拟了一个MFC程序. 但是上一讲留下了疑问. 就是WinMain在哪.以及消息处理在哪里. 这一节主要就是讲解Winmain在哪里. ...