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…

到此本文就結束了,關注公衆號查看更多推送!!!


關注個人公衆號
相關文章
相關標籤/搜索