spring cache 与redis缓存整合

时间:2025-04-03 07:59:42

 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了