美文网首页Java 杂谈java相关
JAVA缓存-Redis入门级使用

JAVA缓存-Redis入门级使用

作者: liangzzz | 来源:发表于2018-09-04 14:19 被阅读510次

    前言

    Java缓存实现方案有很多,最基本的自己使用Map去构建缓存,再高级点的使用Ehcache或者Goolgeguava作为内存缓存框架,Ehcache可以满足单机缓存的需求(Ehcache的具体使用在我过往的文章中有所介绍),如果我们是多台机子共用缓存数据的话,Ehcache可通过rmijgroupjms的方式实现,但是实用性与操作性不高且复杂,现时大部分应用仅用Ehcache作为单机缓存使用,这时候我们可以通过搭建缓存服务器解决多机使用的问题,常见的缓存服务器有MemcachedRedis等。

    现时业界主流大多使用Redis。所以本文主要介绍在Java中如何使用Redis。至于如何搭建Redis,我在过往的文章中已有所介绍,不知道如何搭建的同学,可以参考我过往的文章,下文所用到相关的Redis信息均为搭建教程中的信息。

    PS:文章中所用到的示例代码,部分参考至开源项目iBase4J,特此声明。

    Java连接Redis

    Java连接Redis官方推荐的是使用JedisRedisson进行连接操作,SpringRedis有很好的支持,所以此文我结合Spring中的Spring DataRedis进行操作。

    1. maven引用

    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>1.8.7.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson</artifactId>
        <version>3.5.5</version>
    </dependency>
    

    2. 建立Redis配置文件

    classpath下建立Redis配置文件redis.properties

    如果同学们是搭建Redis高可用架构,是通过向外提供VIP虚拟IP的方式连接Redis,则只需在配置文件中将redis.host=172.16.2.185单机IP改为VIP虚拟IPredis.host=172.16.2.250即可实现Redis高可用,而不需要使用Spring提供的RedisSentinel方案实现Redis高可用。

    #VIP
    #redis.host=172.16.2.250
    redis.host=172.16.2.185
    redis.port=6379
    redis.password=123456
    #最小空闲数
    redis.minIdle=2
    #最大空闲数
    redis.maxIdle=10
    #最大连接数
    redis.maxTotal=1000
    #最大建立连接等待时间
    redis.maxWaitMillis=3000
    #客户端超时时间单位是毫秒
    redis.timeout=120000
    #明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个  
    redis.testOnBorrow=true
    redis.expiration=600
    

    3. 与Spring结合

    3.1 配置Jedis实现

    classpath下建立文件夹spring用于存放所有与spring相关的配置文件。在spring文件夹下建立spring-redis.xml,主要用于注入Jedis

    <?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"
    >
        <context:property-placeholder location="classpath*:redis.properties" ignore-unresolvable="true"/>
        
        <!-- jedis 配置-->
        <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" >
            <!--最小空闲数-->  
            <property name="minIdle" value="${redis.minIdle}" />
            <!--最大空闲数-->  
            <property name="maxIdle" value="${redis.maxIdle}" />
            <!--最大连接数-->  
            <property name="maxTotal" value="${redis.maxTotal}" />
            <!--最大建立连接等待时间-->  
            <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
            <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个-->  
            <property name="testOnBorrow" value="${redis.testOnBorrow}" />  
        </bean >
            
        <!-- redis服务器中心 -->
        <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
          <property name="poolConfig" ref="jedisPoolConfig"/>
          <property name="port" value="${redis.port}"/>
          <property name="hostName" value="${redis.host}"/>
          <property name="password" value="${redis.password}"/>
          <property name="timeout" value="${redis.timeout}" />
      </bean>
        <!-- 缓存序列化方式 -->
        <bean id="keySerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        
        <bean id="valueSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
        
        <!-- 缓存 -->
        <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
            <property name="connectionFactory" ref="jedisConnectionFactory" />
            <property name="enableTransactionSupport" value="true" />
            <property name="keySerializer" ref="keySerializer" />
            <property name="valueSerializer" ref="valueSerializer" />
            <property name="hashKeySerializer" ref="keySerializer" />
            <property name="hashValueSerializer" ref="valueSerializer" />
        </bean>
        
        <bean class="com.easylink.mall.core.cache.redis.RedisHelper" >
            <property name="redisTemplate" ref="redisTemplate" />
        </bean>
        <!-- 缓存管理 -->
        <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
            <constructor-arg index="0" ref="redisTemplate" />
            <property name="transactionAware" value="true" />
            <property name="defaultExpiration" value="${redis.expiration}" />
        </bean>
    </beans>
    
    3.2 配置Redisson实现

    spring文件夹下建立spring-redisson.xml,主要用于注入Redisson

    <?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"
    >
        <context:property-placeholder location="classpath*:redis.properties" ignore-unresolvable="true"/>
        
        <!-- redisson 配置-->
        <bean id="redissonClient" class="com.easylink.mall.core.cache.redisson.Client" init-method="init">
            <property name="password" value="${redis.password}" />
            <!-- SingleServer -->
            <property name="address" value="redis://${redis.host}:${redis.port}" />
            <!-- ClusterServers -->
            <!-- <property name="nodeAddresses" value="${redis.cluster}}" /> -->
            <!-- MasterSlaveServers -->
            <!-- <property name="masterAddress" value="${redis.master}" />
            <property name="slaveAddresses" value="${redis.slave}" /> -->
        </bean>
        
        <!-- redisson 工具类 -->
        <bean class="com.easylink.mall.core.cache.redisson.RedissonHelper">
            <property name="redissonClient" ref="redissonClient" />
        </bean>
    </beans>
    

    4. 代码实现

    4.1 定义获取缓存的工具类CacheUtil

    这个类主要是用于获取缓存管理器,因为Jedis封装Redis基本操作的接口比较友好,所以基本操作使用Jedis实现,但是将Redis当做分布式锁使用时,如果是自行用Jedis中的setNX + 时间戳过程方法实现的话,会略显复杂,还可能写的不严谨,存在原子性操作或者死锁等问题。此处的分布式锁实现使用Redisson帮我们封装好的方法实现加锁与解锁,顺便提一句,Redisson加锁操作是使用lua脚本一次执行加锁与设置过期的操作的,所以不存在原子性问题。这处暂时不展开讨论分布式锁的问题,日后有空再和大家一同探讨分布式锁的问题。

    package com.easylink.mall.core.cache.redis;
    
    import com.easylink.mall.core.support.util.PropertiesFileUtil;
    
    public class CacheUtil {
        /**
         * 缓存管理器,主要执行缓存操作
         */
        private static CacheManager cacheManager;
        /**
         * 锁管理器,主要执行加锁与解锁操作
         */
        private static CacheManager lockManager;
    
        public static void setCacheManager(CacheManager cacheManager) {
            CacheUtil.cacheManager = cacheManager;
        }
    
        public static void setLockManager(CacheManager cacheManager) {
            CacheUtil.lockManager = cacheManager;
        }
    
        public static CacheManager getCache() {
            return cacheManager;
        }
    
        public static CacheManager getLockManager() {
            return lockManager;
        }
    
        /** 获取锁 */
        public static boolean tryLock(String key) {
            int expires = 1000 * PropertiesFileUtil.getInstance("redis.properties").getInt("redis.lock.expires", 180);
            return lockManager.setnx(key, expires);
        }
    
        /** 获取锁 */
        public static boolean getLock(String key) {
            return lockManager.lock(key);
        }
    
        /** 解锁 */
        public static void unlock(String key) {
            lockManager.unlock(key);
        }
    }
    
    4.2 定义缓存操作管理接口CacheManager
    package com.easylink.mall.core.cache.redis;
    
    import java.io.Serializable;
    import java.util.Set;
    
    /**
     * 缓存操作管理接口
     * 
     * @author Ben.
     *
     */
    public interface CacheManager {
        /**
         * 根据key获取对象
         * 
         * @param key
         * @return
         */
        Object get(final String key);
    
        /**
         * 根据正则表达式获取对象
         * 
         * @param pattern
         *            正则表达式
         * @return
         */
        Set<Object> getAll(final String pattern);
    
        /**
         * 设置key-value
         * 
         * @param key
         * @param value
         * @param seconds
         *            过期时间(秒)
         */
        void set(final String key, final Serializable value, int seconds);
    
        /**
         * 设置key-value 过期时间使用默认配置值
         * 
         * @param key
         * @param value
         */
        void set(final String key, final Serializable value);
    
        /**
         * 根据key判断某一对象是否存在
         * 
         * @param key
         * @return 是否存在
         */
        Boolean exists(final String key);
    
        /**
         * 根据key删除对象
         * 
         * @param key
         */
        void del(final String key);
    
        /**
         * 根据正则表达式删除对象
         * 
         * @param pattern
         *            正则表达式
         * @return
         */
        void delAll(final String pattern);
    
        /**
         * 根据key获取对应对象的类型
         * 
         * @param key
         * @return 对应对象的类型
         */
        String type(final String key);
    
        /**
         * 设置key的过期时间
         * 
         * @param key
         * @param seconds
         * @return 是否设置成功
         */
        Boolean expire(final String key, final int seconds);
    
        /**
         * 设置key在指定时间点后过期
         * 
         * @param key
         * @param unixTime
         * @return 是否成功
         */
        Boolean expireAt(final String key, final long unixTime);
    
        /**
         * 获取对应key的过期时间
         * 
         * @param key
         * @return
         */
        Long ttl(final String key);
    
        /**
         * 设置新值并返回旧值
         * 
         * @param key
         * @param value
         * @return 旧值
         */
        Object getSet(final String key, final Serializable value);
    
        /**
         * 对key进行加锁
         * 
         * @param key
         * @return 是否加锁成功
         */
        boolean lock(String key);
    
        /**
         * 对key进行解锁
         * 
         * @param key
         */
        void unlock(String key);
    
        /**
         * 根据key设置对应哈希表对象的field - value
         * 
         * @param key
         * @param field
         * @param value
         */
        void hset(String key, Serializable field, Serializable value);
    
        /**
         * 根据key获取对应哈希表的对应field的对象
         * 
         * @param key
         * @param field
         * @return
         */
        Object hget(String key, Serializable field);
    
        /**
         * 根据key删除对应哈希表的对应field的对象
         * 
         * @param key
         * @param field
         * @return
         */
        void hdel(String key, Serializable field);
    
        /**
         * 指定的 key 不存在时,为 key 设置指定的value
         * 
         * @param key
         * @param value
         * @return 是否设置成功
         */
        boolean setnx(String key, Serializable value);
    
        /**
         * 对应key的值自增
         * 
         * @param key
         * @return 自增后的值
         */
        Long incr(String key);
    
        /**
         * 用指定的字符串覆盖给定 key 所储存的字符串值,覆盖的位置从偏移量 offset 开始
         * 
         * @param key
         * @param offset
         *            偏移量
         * @param value
         */
        void setrange(String key, long offset, String value);
    
        /**
         * 用于获取存储在指定 key 中字符串的子字符串。字符串的截取范围由 start 和 end 两个偏移量决定(包括 start 和 end 在内)。
         * 
         * @param key
         * @param startOffset
         * @param endOffset
         * @return
         */
        String getrange(String key, long startOffset, long endOffset);
    
        /**
         * 将value设置至指定key的set集合中
         * 
         * @param key
         * @param value
         */
        void sadd(String key, Serializable value);
    
        /**
         * 获取指定key的set集合
         * 
         * @param key
         * @return
         */
        Set<?> sall(String key);
    
        /**
         * 删除指定key的set集合中的value
         * 
         * @param key
         * @param value
         * @return
         */
        boolean sdel(String key, Serializable value);
    }
    
    
    4.3 定义RedisHelper

    基于SpringRedisTemplate实现CacheManager接口,主要用于对缓存的基本操作,不用于分布式锁作用,此处的分布式锁实现不严谨,不当做参考

    
    /**
     * Redis缓存辅助类
     * 
     * @author ShenHuaJie
     * @version 2016年4月2日 下午4:17:22
     */
    public final class RedisHelper implements CacheManager {
        private static final Logger logger = Logger.getLogger(RedisHelper.class);
        private RedisSerializer<String> keySerializer;
        private RedisSerializer<Object> valueSerializer;
        private RedisTemplate<Serializable, Serializable> redisTemplate;
        private final Integer EXPIRE = PropertiesFileUtil.getInstance("redis.properties").getInt("redis.expiration");
    
        @SuppressWarnings("unchecked")
        public void setRedisTemplate(RedisTemplate<Serializable, Serializable> redisTemplate) {
            this.redisTemplate = redisTemplate;
            this.keySerializer = (RedisSerializer<String>) redisTemplate.getKeySerializer();
            this.valueSerializer = (RedisSerializer<Object>) redisTemplate.getValueSerializer();
            CacheUtil.setCacheManager(this);
        }
    
        @Override
        public final Object get(final String key) {
            // 先过期
            expire(key, EXPIRE);
            // 后取值
            return redisTemplate.boundValueOps(key).get();
        }
    
        @Override
        public final Set<Object> getAll(final String pattern) {
            Set<Object> values = new HashSet<Object>();
            Set<Serializable> keys = redisTemplate.keys(pattern);
            for (Serializable key : keys) {
                expire(key.toString(), EXPIRE);
                values.add(redisTemplate.opsForValue().get(key));
            }
            return values;
        }
    
        @Override
        public final void set(final String key, final Serializable value, int seconds) {
            redisTemplate.boundValueOps(key).set(value);
            expire(key, seconds);
        }
    
        @Override
        public final void set(final String key, final Serializable value) {
            redisTemplate.boundValueOps(key).set(value);
            expire(key, EXPIRE);
        }
    
        @Override
        public final Boolean exists(final String key) {
            return redisTemplate.hasKey(key);
        }
    
        @Override
        public final void del(final String key) {
            redisTemplate.delete(key);
        }
    
        @Override
        public final void delAll(final String pattern) {
            redisTemplate.delete(redisTemplate.keys(pattern));
        }
    
        @Override
        public final String type(final String key) {
            expire(key, EXPIRE);
            return redisTemplate.type(key).getClass().getName();
        }
    
        @Override
        public final Boolean expire(final String key, final int seconds) {
            return redisTemplate.expire(key, seconds, TimeUnit.SECONDS);
        }
    
    
        @Override
        public final Boolean expireAt(final String key, final long unixTime) {
            return redisTemplate.expireAt(key, new Date(unixTime));
        }
    
        @Override
        public final Long ttl(final String key) {
            return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        }
    
        @Override
        public final void setrange(final String key, final long offset, final String value) {
            redisTemplate.boundValueOps(key).set(value, offset);
            expire(key, EXPIRE);
        }
    
        @Override
        public final String getrange(final String key, final long startOffset, final long endOffset) {
            expire(key, EXPIRE);
            return redisTemplate.boundValueOps(key).get(startOffset, endOffset);
        }
    
        @Override
        public final Object getSet(final String key, final Serializable value) {
            expire(key, EXPIRE);
            return redisTemplate.boundValueOps(key).getAndSet(value);
        }
    
        @Override
        public boolean setnx(String key, Serializable value) {
            RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
            RedisConnection redisConnection = null;
            try {
                redisConnection = RedisConnectionUtils.getConnection(factory);
                if (redisConnection == null) {
                    return redisTemplate.boundValueOps(key).setIfAbsent(value);
                }
                logger.info(keySerializer);
                logger.info(valueSerializer);
                return redisConnection.setNX(keySerializer.serialize(key), valueSerializer.serialize(value));
            } finally {
                RedisConnectionUtils.releaseConnection(redisConnection, factory);
            }
        }
    
        @Override
        public boolean lock(String key) {
            RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
            RedisConnection redisConnection = null;
            try {
                redisConnection = RedisConnectionUtils.getConnection(factory);
                if (redisConnection == null) {
                    return redisTemplate.boundValueOps(key).setIfAbsent("0");
                }
                return redisConnection.setNX(keySerializer.serialize(key), valueSerializer.serialize("0"));
            } finally {
                RedisConnectionUtils.releaseConnection(redisConnection, factory);
            }
        }
    
        @Override
        public void unlock(String key) {
            redisTemplate.delete(key);
        }
    
        @Override
        public void hset(String key, Serializable field, Serializable value) {
            redisTemplate.boundHashOps(key).put(field, value);
        }
    
        @Override
        public Object hget(String key, Serializable field) {
            return redisTemplate.boundHashOps(key).get(field);
        }
    
        @Override
        public void hdel(String key, Serializable field) {
            redisTemplate.boundHashOps(key).delete(field);
        }
    
        @Override
        public void sadd(String key, Serializable value) {
            redisTemplate.boundSetOps(key).add(value);
        }
    
        @Override
        public Set<?> sall(String key) {
            return redisTemplate.boundSetOps(key).members();
        }
    
        @Override
        public boolean sdel(String key, Serializable value) {
            return redisTemplate.boundSetOps(key).remove(value) == 1;
        }
    
        @Override
        public Long incr(String key) {
            return redisTemplate.boundValueOps(key).increment(1L);
        }
    
    }
    
    4.4 定义RedissonHelper

    基于Redisson实现CacheManager接口,主要用于实现基于Redis的分布式锁

    package com.easylink.mall.core.cache.redisson;
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    import org.redisson.api.RBucket;
    import org.redisson.api.RType;
    import org.redisson.api.RedissonClient;
    
    import com.easylink.mall.core.cache.redis.CacheManager;
    import com.easylink.mall.core.cache.redis.CacheUtil;
    import com.easylink.mall.core.support.util.PropertiesFileUtil;
    
    /**
     * 
     * Redis缓存辅助类
     * 
     */
    public class RedissonHelper implements CacheManager {
        private RedissonClient redissonClient;
        private final Integer EXPIRE = PropertiesFileUtil.getInstance("redis.properties").getInt("redis.expiration");
    
        public void setRedissonClient(Client client) {
            this.redissonClient = client.getRedissonClient();
            CacheUtil.setLockManager(this);
        }
    
        private RBucket<Object> getRedisBucket(String key) {
            return redissonClient.getBucket(key);
        }
    
        @Override
        public final Object get(final String key) {
            RBucket<Object> temp = getRedisBucket(key);
            expire(temp, EXPIRE);
            return temp.get();
        }
    
        @Override
        public final void set(final String key, final Serializable value) {
            RBucket<Object> temp = getRedisBucket(key);
            temp.set(value);
            expire(temp, EXPIRE);
        }
    
        @Override
        public final void set(final String key, final Serializable value, int seconds) {
            RBucket<Object> temp = getRedisBucket(key);
            temp.set(value);
            expire(temp, seconds);
        }
    
        public final void multiSet(final Map<String, Object> temps) {
            redissonClient.getBuckets().set(temps);
        }
    
        @Override
        public final Boolean exists(final String key) {
            RBucket<Object> temp = getRedisBucket(key);
            return temp.isExists();
        }
    
        @Override
        public final void del(final String key) {
            redissonClient.getKeys().delete(key);
        }
    
        @Override
        public final void delAll(final String pattern) {
            redissonClient.getKeys().deleteByPattern(pattern);
        }
    
        @Override
        public final String type(final String key) {
            RType type = redissonClient.getKeys().getType(key);
            if (type == null) {
                return null;
            }
            return type.getClass().getName();
        }
    
        /**
         * 在某段时间后失效
         * 
         * @return
         */
        private final void expire(final RBucket<Object> bucket, final int seconds) {
            bucket.expire(seconds, TimeUnit.SECONDS);
        }
    
        /**
         * 在某个时间点失效
         * 
         * @param key
         * @param unixTime
         * @return
         * 
         */
        @Override
        public final Boolean expireAt(final String key, final long unixTime) {
            return redissonClient.getBucket(key).expireAt(new Date(unixTime));
        }
    
        @Override
        public final Long ttl(final String key) {
            RBucket<Object> rBucket = getRedisBucket(key);
            return rBucket.remainTimeToLive();
        }
    
        @Override
        public final Object getSet(final String key, final Serializable value) {
            RBucket<Object> rBucket = getRedisBucket(key);
            return rBucket.getAndSet(value);
        }
    
        @Override
        public Set<Object> getAll(String pattern) {
            Set<Object> set = new HashSet<Object>();
            Iterable<String> keys = redissonClient.getKeys().getKeysByPattern(pattern);
            for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {
                String key = iterator.next();
                set.add(getRedisBucket(key).get());
            }
            return set;
        }
    
        @Override
        public Boolean expire(String key, int seconds) {
            RBucket<Object> bucket = getRedisBucket(key);
            expire(bucket, seconds);
            return true;
        }
    
        @Override
        public void hset(String key, Serializable field, Serializable value) {
            redissonClient.getMap(key).put(field, value);
        }
    
        @Override
        public Object hget(String key, Serializable field) {
            return redissonClient.getMap(key).get(field);
        }
    
        @Override
        public void hdel(String key, Serializable field) {
            redissonClient.getMap(key).remove(field);
        }
    
        public void sadd(String key, Serializable value) {
            redissonClient.getSet(key).add(value);
        }
    
        public Set<Object> sall(String key) {
            return redissonClient.getSet(key).readAll();
        }
    
        public boolean sdel(String key, Serializable value) {
            return redissonClient.getSet(key).remove(value);
        }
    
        @Override
        public boolean lock(String key) {
            return redissonClient.getLock(key).tryLock();
        }
    
        @Override
        public void unlock(String key) {
            redissonClient.getLock(key).unlock();
        }
    
        @Override
        public boolean setnx(String key, Serializable value) {
            try {
                return redissonClient.getLock(key).tryLock(Long.valueOf(value.toString()), TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                return false;
            }
        }
    
        @Override
        public Long incr(String key) {
            return null;
        }
    
        @Override
        public void setrange(String key, long offset, String value) {
        }
    
        @Override
        public String getrange(String key, long startOffset, long endOffset) {
            return null;
        }
    }
    
    4.5 定义Redisson客户端配置实现类
    package com.easylink.mall.core.cache.redisson;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import org.apache.commons.lang3.StringUtils;
    import org.redisson.Redisson;
    import org.redisson.api.RedissonClient;
    import org.redisson.config.ClusterServersConfig;
    import org.redisson.config.Config;
    import org.redisson.config.MasterSlaveServersConfig;
    import org.redisson.config.SingleServerConfig;
    
    /**
     * Redis连接配置
     * 
     * @author ShenHuaJie
     * @since 2017年8月23日 上午9:36:53
     */
    public class Client {
        /**
         * Redis server address
         *
         */
        private String address;
    
        /**
         * Password for Redis authentication. Should be null if not needed
         */
        private String password;
    
        /**
         * Redis cluster node urls list
         */
        private Set<String> nodeAddresses = new HashSet<String>();
    
        /**
         * Redis master server address
         */
        private String masterAddress;
    
        /**
         * Redis slave servers addresses
         */
        private Set<String> slaveAddresses = new HashSet<String>();
    
        private RedissonClient redissonClient;
    
        public void init() {
            Config config = new Config();
            if (StringUtils.isNotBlank(address)) {
                SingleServerConfig serverConfig = config.useSingleServer().setAddress(address);
                if (StringUtils.isNotBlank(password)) {
                    serverConfig.setPassword(password);
                }
            } else if (!nodeAddresses.isEmpty()) {
                ClusterServersConfig serverConfig = config.useClusterServers()
                        .addNodeAddress(nodeAddresses.toArray(new String[] {}));
                if (StringUtils.isNotBlank(password)) {
                    serverConfig.setPassword(password);
                }
            } else if (masterAddress != null && !slaveAddresses.isEmpty()) {
                MasterSlaveServersConfig serverConfig = config.useMasterSlaveServers().setMasterAddress(masterAddress)
                        .addSlaveAddress(slaveAddresses.toArray(new String[] {}));
                if (StringUtils.isNotBlank(password)) {
                    serverConfig.setPassword(password);
                }
            }
            this.redissonClient = Redisson.create(config);
        }
    
        public RedissonClient getRedissonClient() {
            return redissonClient;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public void setNodeAddresses(String nodeAddresse) {
            if (nodeAddresse != null) {
                String[] nodeAddresses = nodeAddresse.split(",");
                for (int i = 0; i < nodeAddresses.length; i++) {
                    if (StringUtils.isNotEmpty(nodeAddresses[i])) {
                        this.nodeAddresses.add(nodeAddresses[i]);
                    }
                }
            }
        }
    
        public void setMasterAddress(String masterAddress) {
            this.masterAddress = masterAddress;
        }
    
        public void setSlaveAddresses(String slaveAddresse) {
            if (slaveAddresse != null) {
                String[] slaveAddresses = slaveAddresse.split(",");
                for (int i = 0; i < slaveAddresses.length; i++) {
                    if (StringUtils.isNotEmpty(slaveAddresses[i])) {
                        this.slaveAddresses.add(slaveAddresses[i]);
                    }
                }
            }
        }
    }
    
    
    4.6 定义properties配置文件读取工具类
    package com.easylink.mall.core.support.util;
    
    import java.util.HashMap;
    
    import org.apache.commons.configuration2.PropertiesConfiguration;
    import org.apache.commons.configuration2.builder.fluent.Configurations;
    import org.apache.commons.configuration2.ex.ConfigurationException;
    import org.apache.log4j.Logger;
    
    /**
     * 资源文件读取工具
     * 
     * @author Ben.
     *
     */
    public class PropertiesFileUtil {
    
        private static Logger logger = Logger.getLogger(PropertiesFileUtil.class);
        // 当打开多个资源文件时,缓存资源文件
        private static HashMap<String, PropertiesConfiguration> configMap = new HashMap<String, PropertiesConfiguration>();
        // 默认资源文件名称
        private static final String NAME = "config.properties";
    
        // 私有构造方法,创建单例
        private PropertiesFileUtil() {
        }
    
        public static synchronized PropertiesConfiguration getInstance() {
            return getInstance(NAME);
        }
    
        public static synchronized PropertiesConfiguration getInstance(String name) {
            PropertiesConfiguration propertiesConfiguration = configMap.get(name);
            if (propertiesConfiguration == null) {
                Configurations configs = new Configurations();
                try {
                    propertiesConfiguration = configs.properties(name);
                } catch (ConfigurationException e) {
                    logger.error("can not load properties file,name : " + name);
                }
                configMap.put(name, propertiesConfiguration);
            }
            return propertiesConfiguration;
        }
    }
    
    

    5. 测试

    编写单元测试用例,测试是否搭建成功

    5.1 测试基本操作
    package com.easylink.mall.core.test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.easylink.mall.core.cache.redis.CacheUtil;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:spring/spring-redis.xml")
    public class JedisTest {
    
         @Test
        public void execute() {
            CacheUtil.getCache().set("test-jedis", "test-value");
            Object testValue = CacheUtil.getCache().get("test-jedis");
            System.out.println(String.valueOf(testValue));
        }
    
    }
    
    
    5.2 测试分布式锁
    package com.easylink.mall.core.test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.easylink.mall.core.cache.redis.CacheUtil;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:spring/spring-redisson.xml")
    public class RedissonTest {
    
        @Test
        public void execute() {
            // 加锁
            CacheUtil.getLockManager().lock("test-jedis");
            // 解锁
            CacheUtil.getLockManager().unlock("test-jedis");
        }
    
    }
    
    

    总结

    至此,上述过程已经说明了如何在JAVA中使用Redis进行一些缓存的基本操作或者是当作分布式锁去使用。内容比较简单,基础。但是适用于初学者去学习,毕竟先学会入门的使用,然后再对其的某些功能或者特性去深入研究,这样能让自己更好的去学习一种技术。楼主由于太久没有更新文章,所以先写一篇简单的找一下感觉。迟点再和大家一同探究Redis的一些知识和常见问题,如:基础的数据结构,缓存和数据库一致性问题,缓存雪崩问题,缓存击穿问题等。谢谢大家的支持,如果此文对你有所帮助,请点个赞,谢谢。

    相关文章

      网友评论

        本文标题:JAVA缓存-Redis入门级使用

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