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

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


环境准备

· redis 

· IDEA 开发工具

· JDK 1.8及以上

· Maven 4.0及以上
复制代码

redis的搭建网上有不少例子,这里就不细讲了,友友们能够网上浏览安装一波,下面咱们就直接讲如何在spring中集成redis。git

资源配置

一、spring集成redis

第一步咱们先设置maven的pom.xml引用,代码以下:github

<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

<!-- redis -->
<import resource="spring-redis.xml" />
复制代码

spring-redis.xml 文件:spring

<?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 配置文件,主要配置具体的参数值:apache

# 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
复制代码

二、Redis客户端编写

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

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存储器。bash

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的简单示例就完成了。

结语

源码地址:github.com/YClimb/redi…

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


关注个人公众号
相关文章
相关标签/搜索