美文网首页redis学习redis我爱编程
Redis 和 Spring 基础整合

Redis 和 Spring 基础整合

作者: 后端技术学习分享 | 来源:发表于2018-04-13 15:35 被阅读19次

    只使用了Redis的单节点连接配置, JedisCluster 和 Sentinel 已被注释,未测试。

    SSM项目搭建

    参考 SSM项目简单整合

    建立配置文件
    • pom.xml 中需添加以下依赖
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.8.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.6.4.RELEASE</version>
    </dependency>
    
    • spring-redis.xml
    <?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:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd 
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context.xsd">
            
        <!-- spring扫描此包下附带注解的类,将其作为bean管理-->
        <context:component-scan base-package="com.yingjun.ssm.cache" />
    
        <!-- 引入redis配置 -->
        <context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>
    
        <!-- Jedis 配置 -->
        <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <property name="maxTotal" value="${redis.pool.maxTotal}" />
            <property name="maxIdle" value="${redis.pool.maxIdle}" />
            <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
            <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
        </bean>
        <!-- redisTemplate配置,redisTemplate是对Jedis的对redis操作的扩展,有更多的操作,封装使操作更便捷 -->
        <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
            <property name="connectionFactory" ref="jedisConnectionFactory" />
        </bean>
        <!-- redis单节点数据库连接配置 -->
        <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
            <property name="hostName" value="${redis.ip}" />
            <property name="port" value="${redis.port}" />
            <property name="password" value="${redis.pass}" />
            <property name="poolConfig" ref="jedisPoolConfig" />
        </bean>
        <!-- JedisCluster 集群高可用配置 -->
        <!--<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
            <constructor-arg index="0">
                <set>
                    <bean class="redis.clients.jedis.HostAndPort">
                        <constructor-arg index="0" value="${redis.ip1}" />
                        <constructor-arg index="1" value="${redis.port1}" type="int" />
                    </bean>
                    <bean class="redis.clients.jedis.HostAndPort">
                        <constructor-arg index="0" value="${redis.ip2}" />
                        <constructor-arg index="1" value="${redis.port2}" type="int" />
                    </bean>
                    <bean class="redis.clients.jedis.HostAndPort">
                        <constructor-arg index="0" value="${redis.ip3}" />
                        <constructor-arg index="1" value="${redis.port3}" type="int" />
                    </bean>
                    <bean class="redis.clients.jedis.HostAndPort">
                        <constructor-arg index="0" value="${redis.ip4}" />
                        <constructor-arg index="1" value="${redis.port4}" type="int" />
                    </bean>
                    <bean class="redis.clients.jedis.HostAndPort">
                        <constructor-arg index="0" value="${redis.ip5}" />
                        <constructor-arg index="1" value="${redis.port5}" type="int" />
                    </bean>
                    <bean class="redis.clients.jedis.HostAndPort">
                        <constructor-arg index="0" value="${redis.ip6}" />
                        <constructor-arg index="1" value="${redis.port6}" type="int" />
                    </bean>
                </set>
            </constructor-arg>
            <constructor-arg index="1" value="2000" type="int"></constructor-arg>
            <constructor-arg index="2" value="100" type="int"></constructor-arg>
            <constructor-arg index="3" ref="jedisPoolConfig"></constructor-arg>
        </bean>-->
        <!--redis Sentinel主从高可用方案配置 -->
        <!-- <bean id="sentinelConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
            <property name="master">
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <property name="name" value="master-1"></property>
                </bean>
            </property>
            <property name="sentinels">
                <set>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="${sentinel1.ip}"></constructor-arg>
                        <constructor-arg name="port" value="${sentinel1.port}"></constructor-arg>
                    </bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="${sentinel2.ip}"></constructor-arg>
                        <constructor-arg name="port" value="${sentinel2.port}"></constructor-arg>
                    </bean>
                    <bean class="org.springframework.data.redis.connection.RedisNode">
                        <constructor-arg name="host" value="${sentinel3.ip}"></constructor-arg>
                        <constructor-arg name="port" value="${sentinel3.port}"></constructor-arg>
                    </bean>
                </set>
            </property>
        </bean>
        <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:use-pool="true">
            <property name="password" value="${redis.pass}" />
            <property name="poolConfig">
                <ref bean="jedisPoolConfig" />
            </property>
            <constructor-arg name="sentinelConfig" ref="sentinelConfiguration" />
        </bean> -->
    </beans>
    
    
    • redis.properties
    # Redis Config
    
    #redis server ip and port
    redis.ip=127.0.0.1
    redis.port=6379
    # Redis server password
    redis.pass=0000
    
    # 最大连接数
    redis.pool.maxTotal=105
    # 最大空闲数
    redis.pool.maxIdle=10
    # 最大建立连接等待时间
    redis.pool.maxWaitMillis=5000
    # 指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
    redis.pool.testOnBorrow=true
    
    
    # redis sentinel config
    #sentinel1.ip=192.168.11.100
    #sentinel1.port=63791
    #sentinel2.ip=192.168.11.101
    #sentinel2.port=63792
    #sentinel3.ip=192.168.11.102
    #sentinel3.port=63792
    
    # reids cluster config
    #redis.ip1=192.168.11.100
    #redis.port1=7111
    #redis.ip2=192.168.11.101
    #redis.port2=7112
    #redis.ip3=192.168.11.102
    #redis.port3=7113
    #redis.ip4=192.168.11.103
    #redis.port4=7114
    #redis.ip5=192.168.11.104
    #redis.port5=7115
    #redis.ip6=192.168.11.105
    #redis.port6=7116
    
    Redis工具类

    此工具类的内部实现原理请在开发工具中查看函数源码

    package com.yingjun.ssm.cache;
    
    import com.yingjun.ssm.util.ProtoStuffSerializerUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    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.stereotype.Component;
    
    import java.util.List;
    import java.util.Set;
    
    /**
     * redis缓存
     * @author yingjun
     *
     */
    @Component
    public class RedisCache {
    
        public final static int CAHCETIME=60;//默认缓存时间
    
        @Autowired
        private RedisTemplate<String, String> redisTemplate;
    
        /**
         * 存入缓存
         * @param key
         * @param obj
         * @param <T>
         * @return
         */
        public <T> boolean putCache(String key, T obj) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);//将对象序列化为byte
            boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
                @Override
                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.setNX(bkey, bvalue);
                }
            });
            return result;
        }
    
        /**
         * 存入缓存并设置有效时间
         * @param key
         * @param obj
         * @param expireTime
         * @param <T>
         */
        public <T> void putCacheWithExpireTime(String key, T obj, final long expireTime) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
            redisTemplate.execute(new RedisCallback<Boolean>() {
                @Override
                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                    connection.setEx(bkey, expireTime, bvalue);
                    return true;
                }
            });
        }
    
        /**
         * 存入list到缓存
         * @param key
         * @param objList
         * @param <T>
         * @return
         */
        public <T> boolean putListCache(String key, List<T> objList) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
            boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
                @Override
                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.setNX(bkey, bvalue);
                }
            });
            return result;
        }
    
        /**
         * 存入list到缓存,并设置有效时间
         * @param key
         * @param objList
         * @param expireTime
         * @param <T>
         * @return
         */
        public <T> boolean putListCacheWithExpireTime(String key, List<T> objList, final long expireTime) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
            boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
                @Override
                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                    connection.setEx(bkey, expireTime, bvalue);
                    return true;
                }
            });
            return result;
        }
    
        /**
         * 根据key读取缓存
         * @param key
         * @param targetClass
         * @param <T>
         * @return
         */
        public <T> T getCache(final String key, Class<T> targetClass) {
            byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
                @Override
                public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.get(key.getBytes());
                }
            });
            if (result == null) {
                return null;
            }
            return ProtoStuffSerializerUtil.deserialize(result, targetClass);
        }
    
        /**
         * 根据key从缓存中读取数组
         * @param key
         * @param targetClass
         * @param <T>
         * @return
         */
        public <T> List<T> getListCache(final String key, Class<T> targetClass) {
            byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
                @Override
                public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.get(key.getBytes());
                }
            });
            if (result == null) {
                return null;
            }
            return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
        }
    
        /**
         * 精确删除key
         * 
         * @param key
         */
        public void deleteCache(String key) {
            redisTemplate.delete(key);
        }
    
        /**
         * 模糊删除key
         * 
         * @param pattern 使用通配符匹配 比如 goods|* 可以查询到 goods|xx, goods|zz之类的key集合
         */
        public void deleteCacheWithPattern(String pattern) {
            //根据pattern获取模糊匹配的key集合
            Set<String> keys = redisTemplate.keys(pattern);
            //批量删除
            redisTemplate.delete(keys);
        }
    }
    
    
    实际使用
    • 类字段需要注入Redis工具
    @Autowired
    private RedisCache cache;
    
    • 使用举例
    public void putUserInCache(int userIndex, String userName){
        // key的格式自己决定 比如该key的格式为: "test|user|xxxx" 表示test项目的某位用户
        String key = "test" + "|user|" + userIndex;
    
        // 将key-value存入Redis
        cache.putCache(key,userName);
    
        // 根据key取出value,此处value为String类型,所以第二参数需要传入 String.class
        String getName = cache.getCache(key,String.class);
    
        // 清除所有缓存(慎用),使用通配符匹配,则所有test项目的缓存都被删除
        cache.deleteCacheWithPattern("test|*");
    }
    

    采用Jedis Cluster的Redis工具类(未测试)

    • RedisClusterCache.java
    package com.yingjun.ssm.cache;
    
    import com.yingjun.ssm.util.ProtoStuffSerializerUtil;
    import org.springframework.stereotype.Component;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisCluster;
    import redis.clients.jedis.JedisPool;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    
    /**
     * redis缓存
     *
     * 采用Jedis Cluster
     *
     * @author yingjun
     *
     */
    @Component
    public class RedisClusterCache {
        
        
        public final static String CAHCENAME="cache";//缓存名
        public final static int CAHCETIME=60;//默认缓存时间
    
        //@Autowired
        private JedisCluster jedisCluster;
    
    
        public <T> void putCache(String key, T obj) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
            jedisCluster.set(bkey,bvalue);
        }
    
        public <T> void putCacheWithExpireTime(String key, T obj,  int expireTime) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serialize(obj);
            jedisCluster.setex(bkey, expireTime, bvalue);
        }
    
        public <T> void putListCache(String key, List<T> objList) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
            jedisCluster.set(bkey,bvalue);
        }
    
        public <T> void putListCacheWithExpireTime(String key, List<T> objList, int expireTime) {
            final byte[] bkey = key.getBytes();
            final byte[] bvalue = ProtoStuffSerializerUtil.serializeList(objList);
            jedisCluster.setex(bkey, expireTime, bvalue);
        }
    
        public <T> T getCache(final String key, Class<T> targetClass) {
            byte[] result =jedisCluster.get(key.getBytes());
            if (result == null) {
                return null;
            }
            return ProtoStuffSerializerUtil.deserialize(result, targetClass);
        }
    
        public <T> List<T> getListCache(String key, Class<T> targetClass) {
            byte[] result =jedisCluster.get(key.getBytes());
            if (result == null) {
                return null;
            }
            return ProtoStuffSerializerUtil.deserializeList(result, targetClass);
        }
    
        /**
         * 精确删除key
         * 
         * @param key
         */
        public void deleteCache(String key) {
            jedisCluster.del(key);
        }
    
        /**
         * 模糊删除key
         * 
         * @param pattern
         */
        public void deleteCacheWithPattern(String pattern) {
            Set<String> keys =this.keys(pattern);
            for(String key:keys){
                jedisCluster.del(key);
            }
        }
    
        /**
         * 清空所有缓存
         */
        public void clearCache() {
            deleteCacheWithPattern(RedisClusterCache.CAHCENAME+"|*");
        }
    
        /**
         * 由于JedisCluster没有提供对keys命令的封装,只能自己实现
         * @param pattern
         * @return
         */
        public Set<String> keys(String pattern){
            Set<String> keys = new HashSet<>();
            Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();
            for(String k : clusterNodes.keySet()){
                JedisPool jp = clusterNodes.get(k);
                Jedis connection = jp.getResource();
                try {
                    keys.addAll(connection.keys(pattern));
                } catch(Exception e){
                    e.printStackTrace();
                } finally{
                    //用完一定要close这个链接!!!
                    connection.close();
                }
            }
            return keys;
        }
    }
    
    
    参考

    源码来自:优雅的SSM(Spring+SpringMVC+Mybatis)框架
    其他参考:
    windows后台运行redis
    Spring整合redis,通过sentinel进行主从切换。(何志雄)
    redis整合spring(redisTemplate工具类)
    Spring-Data-Redis存储对象(redisTemplate)
    Redis官方文档

    相关文章

      网友评论

        本文标题:Redis 和 Spring 基础整合

        本文链接:https://www.haomeiwen.com/subject/rjwckftx.html