本文主要是介绍在windows下的Jeesite框架下集成Redis集群,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
最近想使用Redis集群做缓存,由于公司一直在用Jeesite框架,所以尝试了一下两者进行集成。
Jeesite原本就支持EhCache和Redis两种方式做数据缓存,但并没有做Redis集群。
本以为简单的配置就能实现,没想到调查了整整一天,所以觉得有必要把整个配置过程和踩过的坑记录下来,方便大家使用。
一. Redis安装与配置:
1. 去GitHub下下载win64的Redis:https://github.com/MSOpenTech/redis/releases
2. 解压后可以在redis.windows.conf中修改配置,默认端口是6379
3. 在cmd中执行以下命令启动Redis,我这里的端口是6378
redis-server.exe redis.windows.conf
4. 另外开一个cmd,输入以下命令启动Redis客户端:
redis-cli.exe -h 127.0.0.1 -p 6378
5. Redis的命令介绍可以去这里看:http://www.runoob.com/redis/redis-tutorial.html
6. 当Redis服务器会定期持久化到硬盘,这些都可以在redis.windows.conf里面配置。
默认保存在当前Redis目录下,文件名是dump.rdb
二. Redis集群的配置与启动:
我这里启动6个Redis做3主3从的集群。
1. 先将Redis复制6份
修改各自的redis.windows.conf中下列属性,并启动各个Redis服务:
port 6379(6379-6384)
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes
2. win64版的Redis包下面由于没有redis-trib.rb,所以无法启动集群,需要去Redis官网下载Linux版的包后,在src文件夹下找到这个文件。
执行这个文件需要Ruby,可以去这里下载:http://railsinstaller.org/en
安装并执行下面的命令进行配置
3. 将redis-trib.rb拷到RailsInstaller下面启动集群
ruby redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
--replicas 1 :表示在1个主节点后创建1个从节点
我在测试中遇到下面这个错误:
这是因为我已经启动了6380服务器并且手动给它分配过节点的关系,假如遇到这种情况就把Redis服务停止,删除Redis目录下面的appendonly.aof,dump.rdb,nodes.conf,重启即可。
配置正确的情况下,会提示你集群信息,确认无误输入yes,redis-trib就会开始启动集群了。
这时候去各个Redis服务下面,可以看到画面不停的有消息在滚动,表明Redis之间开始通信了:
4. 测试集群
在启动redis-cli.exe的时候,记得加上-c,表示以集群模式启动。
redis-cli.exe -c -h 127.0.0.1 -p 6379
输入多个key-value,可以看到集群会自动将他们分配到不同的Redis服务器:
从各个服务器上可以看到分别保存了不同的key:
5. 用命令查看和控制集群:
(1). 显示集群状态:
cluster info
(2). 显示集群中所有的节点信息:
cluster nodes
(3). 手动在集群中增加一个节点:
cluster meet 127.0.0.1 6378
(4). 手动删除一个节点:
cluster forget nodeid(就是用cluster nodes命令看到的前面那串数字+字母的ID)
三. Jeesite中的配置修改:
1. spring-context-shiro.xml中,将EhCache相关配置改成Jedis:
<!-- 自定义Session存储容器 --><bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.JedisSessionDAO"><property name="sessionIdGenerator" ref="idGen" /><property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" /></bean>
<!-- <bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.CacheSessionDAO"><property name="sessionIdGenerator" ref="idGen" /><property name="activeSessionsCacheName" value="activeSessionsCache" /><property name="cacheManager" ref="shiroCacheManager" /></bean> --><!-- 自定义系统缓存管理器--><bean id="shiroCacheManager" class="com.thinkgem.jeesite.common.security.shiro.cache.JedisCacheManager"><property name="cacheKeyPrefix" value="${redis.keyPrefix}_cache_" /></bean>
<!-- <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"><property name="cacheManager" ref="cacheManager"/></bean> -->
2. spring-context-jedis.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-4.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"default-lazy-init="true"><description>Jedis Configuration</description><!-- 加载配置属性文件 --><context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" /><bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"><!-- 最大连接数 --> <property name="maxTotal" value="60000" /> <!-- 最大空闲连接数 --> <property name="maxIdle" value="300" /> <!-- 每次释放连接的最大数目 --> <property name="numTestsPerEvictionRun" value="1024" /> <!-- 释放连接的扫描间隔(毫秒) --> <property name="timeBetweenEvictionRunsMillis" value="30000" /> <!-- 连接最小空闲时间 --> <property name="minEvictableIdleTimeMillis" value="1800000" /> <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 --> <property name="softMinEvictableIdleTimeMillis" value="10000" /> <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 --> <property name="maxWaitMillis" value="1500" /> <!-- 在获取连接的时候检查有效性, 默认false --> <property name="testOnBorrow" value="true" /> <!-- 在空闲时检查有效性, 默认false --> <property name="testWhileIdle" value="true" /> <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true --> <property name="blockWhenExhausted" value="false" /> </bean><!-- jedis单机版配置 --><bean id="jedisPool" class="redis.clients.jedis.JedisPool"><constructor-arg index="0" ref="jedisPoolConfig" /><constructor-arg index="1" value="${redis.host}" /><constructor-arg index="2" value="${redis.port}" type="int" /><constructor-arg index="3" value="${redis.timeout}" type="int" /><constructor-arg index="4" value="${redis.password}"/><constructor-arg index="5" value="${redis.database}" type="int" /><constructor-arg index="6" value="${redis.clientName}"/></bean><!-- jedis集群版配置 --><bean id="jedisCluster" class="redis.clients.jedis.JedisCluster"><constructor-arg name="nodes" index="0"><set><bean class="redis.clients.jedis.HostAndPort"><constructor-arg name="host" index="0" value="127.0.0.1"></constructor-arg><constructor-arg name="port" index="1" value="6379"></constructor-arg></bean><bean class="redis.clients.jedis.HostAndPort"><constructor-arg name="host" index="0" value="127.0.0.1"></constructor-arg><constructor-arg name="port" index="1" value="6380"></constructor-arg></bean><bean class="redis.clients.jedis.HostAndPort"><constructor-arg name="host" index="0" value="127.0.0.1"></constructor-arg><constructor-arg name="port" index="1" value="6381"></constructor-arg></bean><bean class="redis.clients.jedis.HostAndPort"><constructor-arg name="host" index="0" value="127.0.0.1"></constructor-arg><constructor-arg name="port" index="1" value="6382"></constructor-arg></bean><bean class="redis.clients.jedis.HostAndPort"><constructor-arg name="host" index="0" value="127.0.0.1"></constructor-arg><constructor-arg name="port" index="1" value="6383"></constructor-arg></bean><bean class="redis.clients.jedis.HostAndPort"><constructor-arg name="host" index="0" value="127.0.0.1"></constructor-arg><constructor-arg name="port" index="1" value="6384"></constructor-arg></bean></set></constructor-arg><!-- <constructor-arg index="1" name="poolConfig" ref="jedisPoolConfig"></constructor-arg> --></bean>
</beans>
3. 顺带一提,单机版的Redis只要改jeesite.properties即可:
#redis settings
redis.keyPrefix=jeesite
redis.host=127.0.0.1
redis.port=6379
四. Jeesite中的代码修改:
由于jeesite中自带了Redis单机版,所以我这里是在单机版的基础上修改代码。
其实主要是因为Jedis里面,单机版的代码和集群版的是两套东西
单机版的写法:
Jedis jedis = jedisPool.getResource();
String value = jedis.get(key);
集群版的写法:
String value = jedisCluster.get(key); // 不需要先getResource
另外,我用的jeesite自带的jedis的版本是2.5.0,需要在pom.xml里面,将版本改为2.9.0,否则有些方法在集群中没有。
1. 增加JedisClusterUtils.java,与JedisUtils.java放在一起:
/*** Copyright © 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.*/
package com.thinkgem.jeesite.common.utils;import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.thinkgem.jeesite.common.config.Global;import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisException;/*** Jedis Cache 工具类* * @author ThinkGem* @version 2014-6-29*/
public class JedisClusterUtils {private static Logger logger = LoggerFactory.getLogger(JedisClusterUtils.class);private static JedisCluster jedisCluster = SpringContextHolder.getBean(JedisCluster.class);public static final String KEY_PREFIX = Global.getConfig("redis.keyPrefix");/*** 获取缓存* @param key 键* @return 值*/public static String get(String key) {String value = null;try {if (jedisCluster.exists(key)) {value = jedisCluster.get(key);value = StringUtils.isNotBlank(value) && !"nil".equalsIgnoreCase(value) ? value : null;logger.debug("get {} = {}", key, value);}} catch (Exception e) {logger.warn("get {} = {}", key, value, e);}return value;}/*** 获取缓存* @param key 键* @return 值*/public static Object getObject(String key) {Object value = null;try {if (jedisCluster.exists(getBytesKey(key))) {value = toObject(jedisCluster.get(getBytesKey(key)));logger.debug("getObject {} = {}", key, value);}} catch (Exception e) {logger.warn("getObject {} = {}", key, value, e);} return value;}/*** 设置缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String set(String key, String value, int cacheSeconds) {String result = null;try {result = jedisCluster.set(key, value);if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("set {} = {}", key, value);} catch (Exception e) {logger.warn("set {} = {}", key, value, e);}return result;}/*** 设置缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String setObject(String key, Object value, int cacheSeconds) {String result = null;try {result = jedisCluster.set(getBytesKey(key), toBytes(value));if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("setObject {} = {}", key, value);} catch (Exception e) {logger.warn("setObject {} = {}", key, value, e);}return result;}/*** 获取List缓存* @param key 键* @return 值*/public static List<String> getList(String key) {List<String> value = null;try {if (jedisCluster.exists(key)) {value = jedisCluster.lrange(key, 0, -1);logger.debug("getList {} = {}", key, value);}} catch (Exception e) {logger.warn("getList {} = {}", key, value, e);}return value;}/*** 获取List缓存* @param key 键* @return 值*/public static List<Object> getObjectList(String key) {List<Object> value = null;try {if (jedisCluster.exists(getBytesKey(key))) {List<byte[]> list = jedisCluster.lrange(getBytesKey(key), 0, -1);value = Lists.newArrayList();for (byte[] bs : list){value.add(toObject(bs));}logger.debug("getObjectList {} = {}", key, value);}} catch (Exception e) {logger.warn("getObjectList {} = {}", key, value, e);}return value;}/*** 设置List缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setList(String key, List<String> value, int cacheSeconds) {long result = 0;Jedis jedis = null;try {if (jedisCluster.exists(key)) {jedisCluster.del(key);}result = jedisCluster.rpush(key, (String[])value.toArray());if (cacheSeconds != 0) {jedis.expire(key, cacheSeconds);}logger.debug("setList {} = {}", key, value);} catch (Exception e) {logger.warn("setList {} = {}", key, value, e);}return result;}/*** 设置List缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setObjectList(String key, List<Object> value, int cacheSeconds) {long result = 0;try {if (jedisCluster.exists(getBytesKey(key))) {jedisCluster.del(key);}List<byte[]> list = Lists.newArrayList();for (Object o : value){list.add(toBytes(o));}result = jedisCluster.rpush(getBytesKey(key), (byte[][])list.toArray());if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("setObjectList {} = {}", key, value);} catch (Exception e) {logger.warn("setObjectList {} = {}", key, value, e);}return result;}/*** 向List缓存中添加值* @param key 键* @param value 值* @return*/public static long listAdd(String key, String... value) {long result = 0;try {result = jedisCluster.rpush(key, value);logger.debug("listAdd {} = {}", key, value);} catch (Exception e) {logger.warn("listAdd {} = {}", key, value, e);}return result;}/*** 向List缓存中添加值* @param key 键* @param value 值* @return*/public static long listObjectAdd(String key, Object... value) {long result = 0;try {List<byte[]> list = Lists.newArrayList();for (Object o : value){list.add(toBytes(o));}result = jedisCluster.rpush(getBytesKey(key), (byte[][])list.toArray());logger.debug("listObjectAdd {} = {}", key, value);} catch (Exception e) {logger.warn("listObjectAdd {} = {}", key, value, e);}return result;}/*** 获取缓存* @param key 键* @return 值*/public static Set<String> getSet(String key) {Set<String> value = null;try {if (jedisCluster.exists(key)) {value = jedisCluster.smembers(key);logger.debug("getSet {} = {}", key, value);}} catch (Exception e) {logger.warn("getSet {} = {}", key, value, e);}return value;}/*** 获取缓存* @param key 键* @return 值*/public static Set<Object> getObjectSet(String key) {Set<Object> value = null;try {if (jedisCluster.exists(getBytesKey(key))) {value = Sets.newHashSet();Set<byte[]> set = jedisCluster.smembers(getBytesKey(key));for (byte[] bs : set){value.add(toObject(bs));}logger.debug("getObjectSet {} = {}", key, value);}} catch (Exception e) {logger.warn("getObjectSet {} = {}", key, value, e);}return value;}/*** 设置Set缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setSet(String key, Set<String> value, int cacheSeconds) {long result = 0;try {if (jedisCluster.exists(key)) {jedisCluster.del(key);}result = jedisCluster.sadd(key, (String[])value.toArray());if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("setSet {} = {}", key, value);} catch (Exception e) {logger.warn("setSet {} = {}", key, value, e);}return result;}/*** 设置Set缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static long setObjectSet(String key, Set<Object> value, int cacheSeconds) {long result = 0;try {if (jedisCluster.exists(getBytesKey(key))) {jedisCluster.del(key);}Set<byte[]> set = Sets.newHashSet();for (Object o : value){set.add(toBytes(o));}result = jedisCluster.sadd(getBytesKey(key), (byte[][])set.toArray());if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("setObjectSet {} = {}", key, value);} catch (Exception e) {logger.warn("setObjectSet {} = {}", key, value, e);}return result;}/*** 向Set缓存中添加值* @param key 键* @param value 值* @return*/public static long setSetAdd(String key, String... value) {long result = 0;try {result = jedisCluster.sadd(key, value);logger.debug("setSetAdd {} = {}", key, value);} catch (Exception e) {logger.warn("setSetAdd {} = {}", key, value, e);}return result;}/*** 向Set缓存中添加值* @param key 键* @param value 值* @return*/public static long setSetObjectAdd(String key, Object... value) {long result = 0;try {Set<byte[]> set = Sets.newHashSet();for (Object o : value){set.add(toBytes(o));}result = jedisCluster.rpush(getBytesKey(key), (byte[][])set.toArray());logger.debug("setSetObjectAdd {} = {}", key, value);} catch (Exception e) {logger.warn("setSetObjectAdd {} = {}", key, value, e);}return result;}/*** 获取Map缓存* @param key 键* @return 值*/public static Map<String, String> getMap(String key) {Map<String, String> value = null;try {if (jedisCluster.exists(key)) {value = jedisCluster.hgetAll(key);logger.debug("getMap {} = {}", key, value);}} catch (Exception e) {logger.warn("getMap {} = {}", key, value, e);}return value;}/*** 获取Map缓存* @param key 键* @return 值*/public static Map<String, Object> getObjectMap(String key) {Map<String, Object> value = null;try {if (jedisCluster.exists(getBytesKey(key))) {value = Maps.newHashMap();Map<byte[], byte[]> map = jedisCluster.hgetAll(getBytesKey(key));for (Map.Entry<byte[], byte[]> e : map.entrySet()){value.put(StringUtils.toString(e.getKey()), toObject(e.getValue()));}logger.debug("getObjectMap {} = {}", key, value);}} catch (Exception e) {logger.warn("getObjectMap {} = {}", key, value, e);}return value;}/*** 设置Map缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String setMap(String key, Map<String, String> value, int cacheSeconds) {String result = null;try {if (jedisCluster.exists(key)) {jedisCluster.del(key);}result = jedisCluster.hmset(key, value);if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("setMap {} = {}", key, value);} catch (Exception e) {logger.warn("setMap {} = {}", key, value, e);}return result;}/*** 设置Map缓存* @param key 键* @param value 值* @param cacheSeconds 超时时间,0为不超时* @return*/public static String setObjectMap(String key, Map<String, Object> value, int cacheSeconds) {String result = null;try {if (jedisCluster.exists(getBytesKey(key))) {jedisCluster.del(key);}Map<byte[], byte[]> map = Maps.newHashMap();for (Map.Entry<String, Object> e : value.entrySet()){map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));}result = jedisCluster.hmset(getBytesKey(key), (Map<byte[], byte[]>)map);if (cacheSeconds != 0) {jedisCluster.expire(key, cacheSeconds);}logger.debug("setObjectMap {} = {}", key, value);} catch (Exception e) {logger.warn("setObjectMap {} = {}", key, value, e);}return result;}/*** 向Map缓存中添加值* @param key 键* @param value 值* @return*/public static String mapPut(String key, Map<String, String> value) {String result = null;try {result = jedisCluster.hmset(key, value);logger.debug("mapPut {} = {}", key, value);} catch (Exception e) {logger.warn("mapPut {} = {}", key, value, e);}return result;}/*** 向Map缓存中添加值* @param key 键* @param value 值* @return*/public static String mapObjectPut(String key, Map<String, Object> value) {String result = null;try {Map<byte[], byte[]> map = Maps.newHashMap();for (Map.Entry<String, Object> e : value.entrySet()){map.put(getBytesKey(e.getKey()), toBytes(e.getValue()));}result = jedisCluster.hmset(getBytesKey(key), (Map<byte[], byte[]>)map);logger.debug("mapObjectPut {} = {}", key, value);} catch (Exception e) {logger.warn("mapObjectPut {} = {}", key, value, e);}return result;}/*** 移除Map缓存中的值* @param key 键* @param value 值* @return*/public static long mapRemove(String key, String mapKey) {long result = 0;try {result = jedisCluster.hdel(key, mapKey);logger.debug("mapRemove {} {}", key, mapKey);} catch (Exception e) {logger.warn("mapRemove {} {}", key, mapKey, e);}return result;}/*** 移除Map缓存中的值* @param key 键* @param value 值* @return*/public static long mapObjectRemove(String key, String mapKey) {long result = 0;try {result = jedisCluster.hdel(getBytesKey(key), getBytesKey(mapKey));logger.debug("mapObjectRemove {} {}", key, mapKey);} catch (Exception e) {logger.warn("mapObjectRemove {} {}", key, mapKey, e);}return result;}/*** 判断Map缓存中的Key是否存在* @param key 键* @param value 值* @return*/public static boolean mapExists(String key, String mapKey) {boolean result = false;try {result = jedisCluster.hexists(key, mapKey);logger.debug("mapExists {} {}", key, mapKey);} catch (Exception e) {logger.warn("mapExists {} {}", key, mapKey, e);}return result;}/*** 判断Map缓存中的Key是否存在* @param key 键* @param value 值* @return*/public static boolean mapObjectExists(String key, String mapKey) {boolean result = false;try {result = jedisCluster.hexists(getBytesKey(key), getBytesKey(mapKey));logger.debug("mapObjectExists {} {}", key, mapKey);} catch (Exception e) {logger.warn("mapObjectExists {} {}", key, mapKey, e);}return result;}/*** 删除缓存* @param key 键* @return*/public static long del(String key) {long result = 0;try {if (jedisCluster.exists(key)){result = jedisCluster.del(key);logger.debug("del {}", key);}else{logger.debug("del {} not exists", key);}} catch (Exception e) {logger.warn("del {}", key, e);}return result;}/*** 删除缓存* @param key 键* @return*/public static long delObject(String key) {long result = 0;try {if (jedisCluster.exists(getBytesKey(key))){result = jedisCluster.del(getBytesKey(key));logger.debug("delObject {}", key);}else{logger.debug("delObject {} not exists", key);}} catch (Exception e) {logger.warn("delObject {}", key, e);}return result;}/*** 缓存是否存在* @param key 键* @return*/public static boolean exists(String key) {boolean result = false;try {result = jedisCluster.exists(key);logger.debug("exists {}", key);} catch (Exception e) {logger.warn("exists {}", key, e);}return result;}/*** 缓存是否存在* @param key 键* @return*/public static boolean existsObject(String key) {boolean result = false;try {result = jedisCluster.exists(getBytesKey(key));logger.debug("existsObject {}", key);} catch (Exception e) {logger.warn("existsObject {}", key, e);}return result;}/*** 获取byte[]类型Key* @param key* @return*/public static byte[] getBytesKey(Object object){if(object instanceof String){return StringUtils.getBytes((String)object);}else{return ObjectUtils.serialize(object);}}/*** 获取byte[]类型Key* @param key* @return*/public static Object getObjectKey(byte[] key){try{return StringUtils.toString(key);}catch(UnsupportedOperationException uoe){try{return JedisClusterUtils.toObject(key);}catch(UnsupportedOperationException uoe2){uoe2.printStackTrace();}}return null;}/*** Object转换byte[]类型* @param key* @return*/public static byte[] toBytes(Object object){return ObjectUtils.serialize(object);}/*** byte[]型转换Object* @param key* @return*/public static Object toObject(byte[] bytes){return ObjectUtils.unserialize(bytes);}public static String hget(String hkey, String key) {return jedisCluster.hget(hkey, key);}public static long hset(String hkey, String key, String value) {return jedisCluster.hset(hkey, key, value);}public static long incr(String key) {return jedisCluster.incr(key);}public static long expire(String key, int second) {return jedisCluster.expire(key, second);}public static long ttl(String key) {return jedisCluster.ttl(key);}public static long hdel(String hkey, String key) {return jedisCluster.hdel(hkey, key);}public static Map<String, String> hgetAll(String hkey) {return jedisCluster.hgetAll(hkey);}public static byte[] get(byte[] bytes) {return jedisCluster.get(bytes);}public static String set(byte[] key, byte[] value) {return jedisCluster.set(key, value);}public static Long hdel(byte[] key) {return jedisCluster.hdel(key);}public static Long hlen(byte[] key) {return jedisCluster.hlen(key);}public static Set<byte[]> hkeys(byte[] key) {return jedisCluster.hkeys(key);}public static Collection<byte[]> hvals(byte[] key) {return jedisCluster.hvals(key);}public static Long hdel(byte[] key, byte[] value) {return jedisCluster.hdel(key, value);}public static Long del(byte[] key) {return jedisCluster.del(key);}public static byte[] hget(byte[] key, byte[] value) {return jedisCluster.hget(key, value);}public static Long hset(byte[] key, byte[] field, byte[] value) {return jedisCluster.hset(key, field, value);}}
2. 修改JedisSessionDAO.java,主要是将有JedisUtils和jedis的地方,全部改成JedisClusterUtils:
/*** Copyright © 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.*/
package com.thinkgem.jeesite.common.security.shiro.session;import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Set;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import redis.clients.jedis.JedisCluster;import com.google.common.collect.Sets;
import com.thinkgem.jeesite.common.config.Global;
import com.thinkgem.jeesite.common.utils.DateUtils;
import com.thinkgem.jeesite.common.utils.JedisClusterUtils;
import com.thinkgem.jeesite.common.utils.SpringContextHolder;
import com.thinkgem.jeesite.common.utils.StringUtils;
import com.thinkgem.jeesite.common.web.Servlets;/*** 自定义授权会话管理类* @author ThinkGem* @version 2014-7-20*/
public class JedisSessionDAO extends AbstractSessionDAO implements SessionDAO {private Logger logger = LoggerFactory.getLogger(getClass());private String sessionKeyPrefix = "shiro_session_";@Overridepublic void update(Session session) throws UnknownSessionException {if (session == null || session.getId() == null) { return;}HttpServletRequest request = Servlets.getRequest();if (request != null){String uri = request.getServletPath();// 如果是静态文件,则不更新SESSIONif (Servlets.isStaticFile(uri)){return;}// 如果是视图文件,则不更新SESSIONif (StringUtils.startsWith(uri, Global.getConfig("web.view.prefix"))&& StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){return;}// 手动控制不更新SESSIONif (Global.NO.equals(request.getParameter("updateSession"))){return;}}try { // 获取登录者编号PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);String principalId = pc != null ? pc.getPrimaryPrincipal().toString() : StringUtils.EMPTY;JedisClusterUtils.hset(sessionKeyPrefix, session.getId().toString(), principalId + "|" + session.getTimeout() + "|" + session.getLastAccessTime().getTime());JedisClusterUtils.set(JedisClusterUtils.getBytesKey(sessionKeyPrefix + session.getId()), JedisClusterUtils.toBytes(session));// 设置超期时间int timeoutSeconds = (int)(session.getTimeout() / 1000);JedisClusterUtils.expire((sessionKeyPrefix + session.getId()), timeoutSeconds);logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : "");} catch (Exception e) {logger.error("update {} {}", session.getId(), request != null ? request.getRequestURI() : "", e);} }@Overridepublic void delete(Session session) {if (session == null || session.getId() == null) {return;}try {JedisClusterUtils.hdel(JedisClusterUtils.getBytesKey(sessionKeyPrefix), JedisClusterUtils.getBytesKey(session.getId().toString()));JedisClusterUtils.del(JedisClusterUtils.getBytesKey(sessionKeyPrefix + session.getId()));logger.debug("delete {} ", session.getId());} catch (Exception e) {logger.error("delete {} ", session.getId(), e);} }@Overridepublic Collection<Session> getActiveSessions() {return getActiveSessions(true);}/*** 获取活动会话* @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)* @return*/@Overridepublic Collection<Session> getActiveSessions(boolean includeLeave) {return getActiveSessions(includeLeave, null, null);}/*** 获取活动会话* @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)* @param principal 根据登录者对象获取活动会话* @param filterSession 不为空,则过滤掉(不包含)这个会话。* @return*/@Overridepublic Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession){Set<Session> sessions = Sets.newHashSet();try {Map<String, String> map = JedisClusterUtils.hgetAll(sessionKeyPrefix);for (Map.Entry<String, String> e : map.entrySet()){if (StringUtils.isNotBlank(e.getKey()) && StringUtils.isNotBlank(e.getValue())){String[] ss = StringUtils.split(e.getValue(), "|");if (ss != null && ss.length == 3){// jedis.exists(sessionKeyPrefix + e.getKey())){// Session session = (Session)JedisClusterUtils.toObject(jedis.get(JedisClusterUtils.getBytesKey(sessionKeyPrefix + e.getKey())));SimpleSession session = new SimpleSession();session.setId(e.getKey());session.setAttribute("principalId", ss[0]);session.setTimeout(Long.valueOf(ss[1]));session.setLastAccessTime(new Date(Long.valueOf(ss[2])));try{// 验证SESSIONsession.validate();boolean isActiveSession = false;// 不包括离线并符合最后访问时间小于等于3分钟条件。if (includeLeave || DateUtils.pastMinutes(session.getLastAccessTime()) <= 3){isActiveSession = true;}// 符合登陆者条件。if (principal != null){PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);if (principal.toString().equals(pc != null ? pc.getPrimaryPrincipal().toString() : StringUtils.EMPTY)){isActiveSession = true;}}// 过滤掉的SESSIONif (filterSession != null && filterSession.getId().equals(session.getId())){isActiveSession = false;}if (isActiveSession){sessions.add(session);}}// SESSION验证失败catch (Exception e2) {JedisClusterUtils.hdel(sessionKeyPrefix, e.getKey());}}// 存储的SESSION不符合规则else{JedisClusterUtils.hdel(sessionKeyPrefix, e.getKey());}}// 存储的SESSION无Valueelse if (StringUtils.isNotBlank(e.getKey())){JedisClusterUtils.hdel(sessionKeyPrefix, e.getKey());}}logger.info("getActiveSessions size: {} ", sessions.size());} catch (Exception e) {logger.error("getActiveSessions", e);}return sessions;}@Overrideprotected Serializable doCreate(Session session) {HttpServletRequest request = Servlets.getRequest();if (request != null){String uri = request.getServletPath();// 如果是静态文件,则不创建SESSIONif (Servlets.isStaticFile(uri)){return null;}}Serializable sessionId = this.generateSessionId(session);this.assignSessionId(session, sessionId);this.update(session);return sessionId;}@Overrideprotected Session doReadSession(Serializable sessionId) {Session s = null;HttpServletRequest request = Servlets.getRequest();if (request != null){String uri = request.getServletPath();// 如果是静态文件,则不获取SESSIONif (Servlets.isStaticFile(uri)){return null;}s = (Session)request.getAttribute("session_"+sessionId);}if (s != null){return s;}Session session = null;try {
// if (jedis.exists(sessionKeyPrefix + sessionId)){session = (Session)JedisClusterUtils.toObject(JedisClusterUtils.get(JedisClusterUtils.getBytesKey(sessionKeyPrefix + sessionId)));
// }logger.debug("doReadSession {} {}", sessionId, request != null ? request.getRequestURI() : "");} catch (Exception e) {logger.error("doReadSession {} {}", sessionId, request != null ? request.getRequestURI() : "", e);} if (request != null && session != null){request.setAttribute("session_"+sessionId, session);}return session;}@Overridepublic Session readSession(Serializable sessionId) throws UnknownSessionException {try{return super.readSession(sessionId);}catch (UnknownSessionException e) {return null;}}public String getSessionKeyPrefix() {return sessionKeyPrefix;}public void setSessionKeyPrefix(String sessionKeyPrefix) {this.sessionKeyPrefix = sessionKeyPrefix;}}
3. 修改JedisCacheManager.java,改法同JedisSessionDAO.java。
/*** Copyright © 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.*/
package com.thinkgem.jeesite.common.security.shiro.cache;import java.util.Collection;
import java.util.Collections;
import java.util.Set;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import redis.clients.jedis.JedisCluster;import com.google.common.collect.Sets;
import com.thinkgem.jeesite.common.utils.JedisClusterUtils;
import com.thinkgem.jeesite.common.utils.SpringContextHolder;
import com.thinkgem.jeesite.common.web.Servlets;/*** 自定义授权缓存管理类* @author ThinkGem* @version 2014-7-20*/
public class JedisCacheManager implements CacheManager {private String cacheKeyPrefix = "shiro_cache_";@Overridepublic <K, V> Cache<K, V> getCache(String name) throws CacheException {return new JedisCache<K, V>(cacheKeyPrefix + name);}public String getCacheKeyPrefix() {return cacheKeyPrefix;}public void setCacheKeyPrefix(String cacheKeyPrefix) {this.cacheKeyPrefix = cacheKeyPrefix;}/*** 自定义授权缓存管理类* @author ThinkGem* @version 2014-7-20*/public class JedisCache<K, V> implements Cache<K, V> {private Logger logger = LoggerFactory.getLogger(getClass());private String cacheKeyName = null;public JedisCache(String cacheKeyName) {this.cacheKeyName = cacheKeyName;
// if (!JedisClusterUtils.exists(cacheKeyName)){
// Map<String, Object> map = Maps.newHashMap();
// JedisClusterUtils.setObjectMap(cacheKeyName, map, 60 * 60 * 24);
// }
// logger.debug("Init: cacheKeyName {} ", cacheKeyName);}@SuppressWarnings("unchecked")@Overridepublic V get(K key) throws CacheException {if (key == null){return null;}V v = null;HttpServletRequest request = Servlets.getRequest();if (request != null){v = (V)request.getAttribute(cacheKeyName);if (v != null){return v;}}V value = null;try {value = (V)JedisClusterUtils.toObject(JedisClusterUtils.hget(JedisClusterUtils.getBytesKey(cacheKeyName), JedisClusterUtils.getBytesKey(key)));logger.debug("get {} {} {}", cacheKeyName, key, request != null ? request.getRequestURI() : "");} catch (Exception e) {logger.error("get {} {} {}", cacheKeyName, key, request != null ? request.getRequestURI() : "", e);}if (request != null && value != null){request.setAttribute(cacheKeyName, value);}return value;}@Overridepublic V put(K key, V value) throws CacheException {if (key == null){return null;}try {JedisClusterUtils.hset(JedisClusterUtils.getBytesKey(cacheKeyName), JedisClusterUtils.getBytesKey(key), JedisClusterUtils.toBytes(value));logger.debug("put {} {} = {}", cacheKeyName, key, value);} catch (Exception e) {logger.error("put {} {}", cacheKeyName, key, e);}return value;}@SuppressWarnings("unchecked")@Overridepublic V remove(K key) throws CacheException {V value = null;try {value = (V)JedisClusterUtils.toObject(JedisClusterUtils.hget(JedisClusterUtils.getBytesKey(cacheKeyName), JedisClusterUtils.getBytesKey(key)));JedisClusterUtils.hdel(JedisClusterUtils.getBytesKey(cacheKeyName), JedisClusterUtils.getBytesKey(key));logger.debug("remove {} {}", cacheKeyName, key);} catch (Exception e) {logger.warn("remove {} {}", cacheKeyName, key, e);}return value;}@Overridepublic void clear() throws CacheException {try {JedisClusterUtils.hdel(JedisClusterUtils.getBytesKey(cacheKeyName));logger.debug("clear {}", cacheKeyName);} catch (Exception e) {logger.error("clear {}", cacheKeyName, e);}}@Overridepublic int size() {int size = 0;try {size = JedisClusterUtils.hlen(JedisClusterUtils.getBytesKey(cacheKeyName)).intValue();logger.debug("size {} {} ", cacheKeyName, size);return size;} catch (Exception e) {logger.error("clear {}", cacheKeyName, e);}return size;}@SuppressWarnings("unchecked")@Overridepublic Set<K> keys() {Set<K> keys = Sets.newHashSet();try {Set<byte[]> set = JedisClusterUtils.hkeys(JedisClusterUtils.getBytesKey(cacheKeyName));for(byte[] key : set){Object obj = (K)JedisClusterUtils.getObjectKey(key);if (obj != null){keys.add((K) obj);}}logger.debug("keys {} {} ", cacheKeyName, keys);return keys;} catch (Exception e) {logger.error("keys {}", cacheKeyName, e);}return keys;}@SuppressWarnings("unchecked")@Overridepublic Collection<V> values() {Collection<V> vals = Collections.emptyList();try {Collection<byte[]> col = JedisClusterUtils.hvals(JedisClusterUtils.getBytesKey(cacheKeyName));for(byte[] val : col){Object obj = JedisClusterUtils.toObject(val);if (obj != null){vals.add((V) obj);}}logger.debug("values {} {} ", cacheKeyName, vals);return vals;} catch (Exception e) {logger.error("values {}", cacheKeyName, e);}return vals;}}
}
五. 测试:
启动项目并登陆后,去Redis客户端用命令可以看到Session和缓存在各Redis服务器中已被分别保存:
查看所有key:
>keys *
六. 相关下载:
文章中用到的Redis相关工具包的下载:Redis相关工具包
项目我就不上传了,数据库配置都是我自己的,上传了也没用,去jeesite的网站下载v1.2版本即可。
这篇关于在windows下的Jeesite框架下集成Redis集群的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!