0

0

spring cache 与redis缓存整合的详细介绍

零下一度

零下一度

发布时间:2017-06-25 10:42:46

|

1450人浏览过

|

来源于php中文网

原创

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

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

我们先配置redis

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

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

redis.host=192.168.0.43redis.port=6379redis.pass=2015redis.maxIdle=50redis.maxActive=50redis.maxWait=50redis.testOnBorrow=trueredis.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文件中了。

 

Favird No-Code Tools
Favird No-Code Tools

无代码工具的聚合器

下载

对应的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()     */@Overridepublic String getName() {return this.name;
    }/* * (non-Javadoc)
     * @see org.springframework.cache.Cache#getNativeCache()     */@Overridepublic Object getNativeCache() {// TODO Auto-generated method stubreturn this.redisTemplate;
    }/* * (non-Javadoc)
     * @see org.springframework.cache.Cache#get(java.lang.Object)     */@Overridepublic 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")
    @Overridepublic <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)     */@Overridepublic 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>() {
                    @Overridepublic Boolean doInRedis(RedisConnection connection) {
                        connection.set(finalKey.getBytes(), SerializableObjectUtil.serialize(finalValue));// 设置超时间                        connection.expire(finalKey.getBytes(), timeout);return true;
                    }
                });
            }
        }
    }/* * 根据Key 删除缓存     */@Overridepublic 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());
                    }
                });
            }
        }
    }/* * 清楚系统缓存     */@Overridepublic 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);

    @Autowiredprivate DalClient dalClient;/* * @Autowired RedisTemplate<?, ?> redisTemplate;     *//** * 根据名称获取自增序列squence的当前值
     * 
     * @param SequenceName 自增序列名称
     * @return 自增序列当前值
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)     */@Overridepublic 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 */@Overridepublic 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 */@Overridepublic 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注解的含义。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

38

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

83

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

97

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

223

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

458

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

169

2026.03.04

Swift iOS架构设计与MVVM模式实战
Swift iOS架构设计与MVVM模式实战

本专题聚焦 Swift 在 iOS 应用架构设计中的实践,系统讲解 MVVM 模式的核心思想、数据绑定机制、模块拆分策略以及组件化开发方法。内容涵盖网络层封装、状态管理、依赖注入与性能优化技巧。通过完整项目案例,帮助开发者构建结构清晰、可维护性强的 iOS 应用架构体系。

246

2026.03.03

C++高性能网络编程与Reactor模型实践
C++高性能网络编程与Reactor模型实践

本专题围绕 C++ 在高性能网络服务开发中的应用展开,深入讲解 Socket 编程、多路复用机制、Reactor 模型设计原理以及线程池协作策略。内容涵盖 epoll 实现机制、内存管理优化、连接管理策略与高并发场景下的性能调优方法。通过构建高并发网络服务器实战案例,帮助开发者掌握 C++ 在底层系统与网络通信领域的核心技术。

34

2026.03.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Spring中文手册
Spring中文手册

共0课时 | 0.6万人学习

马士兵spring视频教程
马士兵spring视频教程

共25课时 | 9.2万人学习

Spring中文手册
Spring中文手册

共0课时 | 0.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号