美文网首页Java技术升华
Spring+Dubbo集成Redis的两种解决方案

Spring+Dubbo集成Redis的两种解决方案

作者: YClimb | 来源:发表于2018-04-17 22:58 被阅读118次

    Spring+Dubbo集成Redis的两种解决方案

    当下我们的系统数据库压力都非常大,解决数据库的瓶颈问题势在必行,为了解决数据库的压力等需求,我们常用的是各种缓存,比如redis,本文就来简单讲解一下如何集成redis缓存存储,附github源码。


    环境准备

    · redis 
    
    · IDEA 开发工具
    
    · JDK 1.8及以上
    
    · Maven 4.0及以上
    

    redis的搭建网上有很多例子,这里就不细讲了,友友们可以网上浏览安装一波,下面我们就直接讲如何在spring中集成redis。

    资源配置

    1、spring集成redis

    第一步我们先设置maven的pom.xml引用,代码如下:

    
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.6.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.7.3</version>
    </dependency>
    

    设置完引用以后,就可以开始着手编写redis在spring中的配置文件了,下面直接上代码 applicationContext.xml 文件:

    <!-- redis -->
    <import resource="spring-redis.xml" />
    

    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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
    
        <!-- 加载redis参数 -->
        <context:property-placeholder location="classpath:redis.properties" />
    
        <!-- 自动注解 -->
        <!--<context:component-scan base-package="service.impl" />-->
    
        <!-- jedis 连接池配置参数: -->
        <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <!-- 设置最大连接数 -->
            <property name="maxTotal" value="${redis.maxActive}"></property>
            <!-- 设置最大空闲数 -->
            <property name="maxIdle" value="${redis.maxIdle}"></property>
            <!-- 设置超时时间 -->
            <property name="maxWaitMillis" value="${redis.maxWait}"></property>
            <property name="testOnBorrow" value="${redis.testOnBorrow}"></property>
            <property name="testOnReturn" value="${redis.testOnReturn}"></property>
        </bean>
    
        <!-- jedis 连接池 连接本地redis服务 构造器注入 -->
        <bean id="pool" class="redis.clients.jedis.JedisPool">
            <constructor-arg index="0" ref="poolConfig"/>
            <constructor-arg index="1" value="${redis.host}"/>
            <constructor-arg index="2" value="${redis.port}"/>
            <constructor-arg index="3" value="${redis.maxWait}"/>
            <constructor-arg index="4" value="${redis.pass}"/>
        </bean>
    
        <!-- redis cache config -->
        <bean id="redisCache" class="client.RedisCache">
            <property name="pool" ref="pool"/>
        </bean>
    
    </beans>
    

    此文件主要描述了jedis的连接池和配置参数,需要注意的是,jedis的版本不同可能会导致具体的参数不一样,比如2.5.1,大家引用的时候如果有其他版本可以看看源码中的属性参数。

    下面是 redis.properties 配置文件,主要配置具体的参数值:

    # Redis settings
    redis.host=localhost
    redis.port=6379
    redis.pass=123456
    
    redis.maxIdle=25
    redis.maxActive=100
    redis.maxWait=1000
    redis.testOnBorrow=false
    redis.testOnReturn=false
    

    2、Redis客户端编写

    环境和资源已经配置完成,下一次可以开始编写我们的redis客户端程序了,代码如下:

    package client;
    
    import com.alibaba.fastjson.JSON;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.util.ResourceBundle;
    
    /**
     *
     * <p>
     *  Redis客户端访问
     * </p>
     *
     * Created by yclimb on 2017/6/8.
     */
    public class RedisClient {
    
        /**
         * 池化管理jedis链接池
         */
        public static JedisPool jedisPool;
    
        static {
    
            //读取相关的配置
            ResourceBundle resourceBundle = ResourceBundle.getBundle("redis");
            int maxActive = Integer.parseInt(resourceBundle.getString("redis.pool.maxActive"));
            int maxIdle = Integer.parseInt(resourceBundle.getString("redis.pool.maxIdle"));
            int maxWait = Integer.parseInt(resourceBundle.getString("redis.pool.maxWait"));
    
            String ip = resourceBundle.getString("redis.ip");
            int port = Integer.parseInt(resourceBundle.getString("redis.port"));
    
            JedisPoolConfig config = new JedisPoolConfig();
            //设置最大连接数
            config.setMaxTotal(maxActive);
            //设置最大空闲数
            config.setMaxIdle(maxIdle);
            //设置超时时间
            config.setMaxWaitMillis(maxWait);
    
            //初始化连接池
            jedisPool = new JedisPool(config, ip, port);
        }
    
        /**
         * 向缓存中设置字符串内容
         * @param key key
         * @param value value
         * @return
         * @throws Exception
         */
        public static boolean  set(String key,String value) throws Exception{
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                jedis.set(key, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }finally{
                jedisPool.returnResource(jedis);
            }
        }
    
        /**
         * 向缓存中设置对象
         * @param key
         * @param value
         * @return
         */
        public static boolean  set(String key,Object value){
            Jedis jedis = null;
            try {
                String objectJson = JSON.toJSONString(value);
                jedis = jedisPool.getResource();
                jedis.set(key, objectJson);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }finally{
                jedisPool.returnResource(jedis);
            }
        }
    
        /**
         * 删除缓存中得对象,根据key
         * @param key
         * @return
         */
        public static boolean del(String key){
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                jedis.del(key);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }finally{
                jedisPool.returnResource(jedis);
            }
        }
    
        /**
         * 根据key 获取内容
         * @param key
         * @return
         */
        public static Object get(String key){
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                Object value = jedis.get(key);
                return value;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }finally{
                jedisPool.returnResource(jedis);
            }
        }
    
    
        /**
         * 根据key 获取对象
         * @param key
         * @return
         */
        public static <T> T get(String key,Class<T> clazz){
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                String value = jedis.get(key);
                return JSON.parseObject(value, clazz);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }finally{
                jedisPool.returnResource(jedis);
            }
        }
    
    
    }
    
    

    此文件是一个简单的redis客户端,可以直接使用此客户端操作jedis的存取方法,Test类如下:

    package test;
    
    import client.RedisClient;
    import entity.City;
    import org.junit.Test;
    
    /**
     *
     * <p>
     *  测试独立redis 客户端
     * </p>
     *
     * Created by yclimb on 2017/6/8.
     */
    public class SimpleClient {
    
        @Test
        public void userCache(){
    
            //向缓存中保存对象
            City city = new City();
            city.setCity("city");
            city.setCity("1");
            city.setLastUpdate("2222");
    
            //调用方法处理
            boolean reusltCache = RedisClient.set("city1", city);
            if (reusltCache) {
                System.out.println("向缓存中保存对象成功。");
            }else{
                System.out.println("向缓存中保存对象失败。");
            }
        }
    
    
        @Test
        public void getUserInfo(){
    
            City city = RedisClient.get("city1", City.class);
            if (city != null) {
                System.out.println("从缓存中获取的对象," + city.getCity() + "@" + city.getLastUpdate());
            }
    
        }
    
    
    
    }
    
    
    

    此时,我们的第一个简单的redis客户端就已经成功了;但是,平时我们都是使用rpc分布式架构,所以说我们还需要一个service接口化的redis存储器,方便dubbo服务调用,下面我们就一起来编写dubbo的redis service存储器。

    dubbo服务化的redis存储器

    首先,我们需要定义一个redis的缓存配置类,主要用户获取和关闭redis连接,需要使用资源配置时的jedis pool,代码如下:

    package client;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    import java.io.Serializable;
    
    /**
     * redis 缓存配置
     * @author yclimb
     */
    public class RedisCache implements Serializable {
    
        /**
         * 日志记录
         */
        private static final Log LOG = LogFactory.getLog(RedisCache.class);
    
        /**
         * redis 连接池
         */
        private JedisPool pool;
        public void setPool(JedisPool pool) {
            this.pool = pool;
        }
    
        /*static {
            if (pool == null) {
                //读取相关的配置
                ResourceBundle resourceBundle = ResourceBundle.getBundle("redis");
                int maxActive = Integer.parseInt(resourceBundle.getString("redis.maxActive"));
                int maxIdle = Integer.parseInt(resourceBundle.getString("redis.maxIdle"));
                int maxWait = Integer.parseInt(resourceBundle.getString("redis.maxWait"));
    
                String host = resourceBundle.getString("redis.host");
                int port = Integer.parseInt(resourceBundle.getString("redis.port"));
                String pass = resourceBundle.getString("redis.pass");
    
                JedisPoolConfig config = new JedisPoolConfig();
                //设置最大连接数
                config.setMaxTotal(maxActive);
                //设置最大空闲数
                config.setMaxIdle(maxIdle);
                //设置超时时间
                config.setMaxWaitMillis(maxWait);
    
                //初始化连接池
                pool = new JedisPool(config, host, port, 2000, pass);
            }
        }*/
    
        /**
         * 获取jedis
         *
         * @return jedis
         */
        public Jedis getResource() {
            Jedis jedis = null;
            try {
                jedis = pool.getResource();
            } catch (Exception e) {
                LOG.info("can't get the redis resource");
            }
            return jedis;
        }
    
        /**
         * 关闭连接
         *
         * @param jedis j
         */
        public void disconnect(Jedis jedis) {
            jedis.disconnect();
        }
    
        /**
         * 将jedis 返还连接池
         *
         * @param jedis j
         */
        public void returnResource(Jedis jedis) {
            if (null != jedis) {
                try {
                    pool.returnResource(jedis);
                } catch (Exception e) {
                    LOG.info("can't return jedis to jedisPool");
                }
            }
        }
    
        /**
         * 无法返还jedispool,释放jedis客户端对象
         *
         * @param jedis j
         */
        public void brokenResource(Jedis jedis) {
            if (jedis != null) {
                try {
                    pool.returnBrokenResource(jedis);
                } catch (Exception e) {
                    LOG.info("can't release jedis Object");
                }
            }
        }
    }
    
    
    

    默认使用spring中给的配置文件,自动注入,也可以使用代码中注释的静态代码块,这个看个人需求。

    有了缓存配置和jedis pool,此时我们就可以开始编写增删改查的service存储器了,代码如下:

    接口:RedisCacheStorageService.java

    package service;
    
    import java.util.Map;
    
    /**
     * 缓存存储接口
     * @author yclimb
     *
     * @param <K> key
     * @param <V> value
     */
    public interface RedisCacheStorageService<K, V> {
        /**
         * 在redis数据库中插入 key  和value
         *
         * @param key
         * @param value
         * @return
         */
        boolean set(K key, V value);
    
        /**
         * 在redis数据库中插入 key  和value 并且设置过期时间
         *
         * @param key
         * @param value
         * @param exp   过期时间 s
         * @return
         */
        boolean set(K key, V value, int exp);
    
        /**
         * 根据key 去redis 中获取value
         *
         * @param key
         * @return
         */
        V get(K key);
    
        /**
         * 删除redis库中的数据
         *
         * @param key
         * @return
         */
        boolean remove(K key);
    
        /**
         * 设置哈希类型数据到redis 数据库
         *
         * @param cacheKey 可以看做一张表
         * @param key      表字段
         * @param value
         * @return
         */
        boolean hset(String cacheKey, K key, V value);
    
        /**
         * 获取哈希表数据类型的值
         *
         * @param cacheKey
         * @param key
         * @return
         */
        V hget(String cacheKey, K key);
    
        /**
         * 获取哈希类型的数据
         *
         * @param cacheKey
         * @return
         */
        Map<K, V> hget(String cacheKey);
    }
    
    

    实现类:RedisCacheStorageServiceImpl.java

    package service.impl;
    
    import client.RedisCache;
    import com.alibaba.fastjson.JSON;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import redis.clients.jedis.Jedis;
    import service.RedisCacheStorageService;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * redis 缓存存储器实现
     * @author yclimb
     *
     * @param <V>
     */
    @Service
    public class RedisCacheStorageServiceImpl<V> implements RedisCacheStorageService<String, V> {
    
        /**
         * 日志记录
         */
        public static final Log LOG = LogFactory.getLog(RedisCacheStorageServiceImpl.class);
    
        /**
         * 默认过时时间(60 * 60 * 24)
         */
        private static final int EXPIRE_TIME = 86400;
    
        @Autowired
        private RedisCache redisCache;
    
        /**
         * 在redis数据库中插入 key和value
         *
         * @param key k
         * @param value v
         * @return boolean
         */
        @Override
        public boolean set(String key, V value) {
            // 设置默认过时时间
            return set(key, value, EXPIRE_TIME);
        }
    
        /**
         * 在redis数据库中插入 key和value 并且设置过期时间
         *
         * @param key k
         * @param value v
         * @param exp   过期时间 s
         * @return boolean
         */
        @Override
        public boolean set(String key, V value, int exp) {
            Jedis jedis = null;
            // 将key 和value  转换成 json 对象
            String jKey = JSON.toJSONString(key);
            String jValue = JSON.toJSONString(value);
            // 操作是否成功
            boolean isSucess = true;
            if (StringUtils.isEmpty(jKey)) {
                LOG.info("key is empty");
                return false;
            }
            try {
                // 获取客户端对象
                jedis = redisCache.getResource();
                // 执行插入
                jedis.setex(jKey, exp, jValue);
            } catch (Exception e) {
                LOG.info("client can't connect server");
                isSucess = false;
                if (null != jedis) {
                    // 释放jedis对象
                    redisCache.brokenResource(jedis);
                }
                return false;
            } finally {
                if (isSucess) {
                    // 返还连接池
                    redisCache.returnResource(jedis);
                }
            }
            return true;
        }
    
        /**
         * 根据key去redis中获取value
         *
         * @param key k
         * @return obj
         */
        @Override
        public V get(String key) {
            Jedis jedis = null;
            // 将key 和value  转换成 json 对象
            String jKey = JSON.toJSONString(key);
            V jValue = null;
            // key 不能为空
            if (StringUtils.isEmpty(jKey)) {
                LOG.info("key is empty");
                return null;
            }
            try {
                // 获取客户端对象
                jedis = redisCache.getResource();
                // 执行查询
                String value = jedis.get(jKey);
                // 判断值是否非空
                if (StringUtils.isEmpty(value)) {
                    return null;
                } else {
                    jValue = (V) JSON.parse(value);
                }
                // 返还连接池
                redisCache.returnResource(jedis);
            } catch (Exception e) {
                LOG.info("client can't connect server");
                if (null != jedis) {
                    // 释放jedis对象
                    redisCache.brokenResource(jedis);
                }
            }
            return jValue;
        }
    
        /**
         * 删除redis库中的数据
         *
         * @param key k
         * @return boolean
         */
        @Override
        public boolean remove(String key) {
            Jedis jedis = null;
            // 将key 和value  转换成 json 对象
            String jKey = JSON.toJSONString(key);
            // 操作是否成功
            boolean isSucess = true;
            if (StringUtils.isEmpty(jKey)) {
                LOG.info("key is empty");
                return false;
            }
            try {
                jedis = redisCache.getResource();
                // 执行删除
                jedis.del(jKey);
            } catch (Exception e) {
                LOG.info("client can't connect server");
                isSucess = false;
                if (null != jedis) {
                    // 释放jedis对象
                    redisCache.brokenResource(jedis);
                }
                return false;
            } finally {
                if (isSucess) {
                    // 返还连接池
                    redisCache.returnResource(jedis);
                }
            }
            return true;
        }
    
        /**
         * 设置哈希类型数据到redis数据库
         *
         * @param cacheKey 可以看做一张表
         * @param key      表字段
         * @param value v
         * @return boolean
         */
        @Override
        public boolean hset(String cacheKey, String key, V value) {
            Jedis jedis = null;
            // 将key 和value  转换成 json 对象
            String jKey = JSON.toJSONString(key);
            String jCacheKey = JSON.toJSONString(cacheKey);
            String jValue = JSON.toJSONString(value);
            // 操作是否成功
            boolean isSucess = true;
            if (StringUtils.isEmpty(jCacheKey)) {
                LOG.info("cacheKey is empty");
                return false;
            }
            try {
                jedis = redisCache.getResource();
                // 执行插入哈希
                jedis.hset(jCacheKey, jKey, jValue);
            } catch (Exception e) {
                LOG.info("client can't connect server");
                isSucess = false;
                if (null != jedis) {
                    // 释放jedis对象
                    redisCache.brokenResource(jedis);
                }
                return false;
            } finally {
                if (isSucess) {
                    // 返还连接池
                    redisCache.returnResource(jedis);
                }
            }
            return true;
        }
    
        /**
         * 获取哈希表数据类型的值
         *
         * @param cacheKey cacheK
         * @param key k
         * @return obj
         */
        @Override
        public V hget(String cacheKey, String key) {
            Jedis jedis = null;
            // 将key 和value  转换成 json 对象
            String jKey = JSON.toJSONString(key);
            String jCacheKey = JSON.toJSONString(cacheKey);
            V jValue = null;
            if (StringUtils.isEmpty(jCacheKey)) {
                LOG.info("cacheKey is empty");
                return null;
            }
            try {
                // 获取客户端对象
                jedis = redisCache.getResource();
                // 执行查询
                String value = jedis.hget(jCacheKey, jKey);
                // 判断值是否非空
                if (StringUtils.isEmpty(value)) {
                    return null;
                } else {
                    jValue = (V) JSON.parse(value);
                }
                // 返还连接池
                redisCache.returnResource(jedis);
            } catch (Exception e) {
                LOG.info("client can't connect server");
                if (null != jedis) {
                    // 释放jedis对象
                    redisCache.brokenResource(jedis);
                }
            }
            return jValue;
        }
    
        /**
         * 获取哈希类型的数据
         *
         * @param cacheKey cacheK
         * @return map
         */
        @Override
        public Map<String, V> hget(String cacheKey) {
            String jCacheKey = JSON.toJSONString(cacheKey);
            // 非空校验
            if (StringUtils.isEmpty(jCacheKey)) {
                LOG.info("cacheKey is empty!");
                return null;
            }
            Jedis jedis = null;
            Map<String, V> result = null;
            try {
                jedis = redisCache.getResource();
                // 获取列表集合
                Map<String, String> map = jedis.hgetAll(jCacheKey);
    
                if (null != map) {
                    for (Map.Entry<String, String> entry : map.entrySet()) {
                        if (result == null) {
                            result = new HashMap<String, V>();
                        }
                        result.put((String) JSON.parse(entry.getKey()), (V) JSON.parse(entry.getValue()));
                    }
                }
            } catch (Exception e) {
                LOG.info("client can't connect server");
                if (null != jedis) {
                    // 释放jedis对象
                    redisCache.brokenResource(jedis);
                }
            }
            return result;
        }
    
    }
    

    到这里我们的存储器就编写完成了,接下来就是看看如何注入dubbo服务了,下面是注入的示例代码:

    <?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:dubbo="http://code.alibabatech.com/schema/dubbo"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://code.alibabatech.com/schema/dubbo
            http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    
        <!-- redis -->
        <dubbo:service timeout="${dubbo-timeout}" retries="${dubbo-retries}" interface="com.yc.redis.RedisCacheStorageService" ref="redisCacheStorageServiceImpl" group="${service.group}" />
    
    </beans>
    

    OK,代码编写完成,这里dubbo服务调用的代码我就不贴上了,各位可以自己试一试,到这里一套基于jedis的简单示例就完成了。

    结语

    源码地址:https://github.com/YClimb/redis-demo

    到此本文就结束了,关注公众号查看更多推送!!!


    关注我的公众号

    相关文章

      网友评论

        本文标题:Spring+Dubbo集成Redis的两种解决方案

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