shiro
提供基于ehcache
的缓存实现,参照相关的实现类,我们可以自定义基于redis
的缓存实现。
ehcache实现
org.apache.shiro
shiro-ehcache
1.4.0
redis实现
自定义cache
ShiroRedisCache.java
package com.sdhs.mob.common.shiro;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* shiro redis 缓存
*
* @author seer
* @date 2018/3/24 11:16
*/
public class ShiroRedisCache implements Cache {
private static Logger LOGGER = LogManager.getLogger(ShiroRedisCache.class);
/**
* key前缀
*/
private static final String REDIS_SHIRO_CACHE_KEY_PREFIX = "redis.shiro.cache_";
/**
* cache name
*/
private String name;
/**
* jedis 连接工厂
*/
private JedisConnectionFactory jedisConnectionFactory;
/**
* 序列化工具
*/
private RedisSerializer serializer = new JdkSerializationRedisSerializer();
/**
* 存储key的redis.list的key值
*/
private String keyListKey;
public ShiroRedisCache(String name, JedisConnectionFactory jedisConnectionFactory) {
this.name = name;
this.jedisConnectionFactory = jedisConnectionFactory;
this.keyListKey = "redis.shiro.cache.key_" + name;
}
@Override
public V get(K key) throws CacheException {
LOGGER.debug("shiro redis cache get.{} K={}", name, key);
RedisConnection redisConnection = null;
V result = null;
try {
redisConnection = jedisConnectionFactory.getConnection();
result = (V) serializer.deserialize(redisConnection.get(serializer.serialize(generateKey(key))));
} catch (Exception e) {
LOGGER.error("shiro redis cache get exception. ", e);
} finally {
if (null != redisConnection) {
redisConnection.close();
}
}
return result;
}
@Override
public V put(K key, V value) throws CacheException {
LOGGER.debug("shiro redis cache put.{} K={} V={}", name, key, value);
RedisConnection redisConnection = null;
V result = null;
try {
redisConnection = jedisConnectionFactory.getConnection();
result = (V) serializer.deserialize(redisConnection.get(serializer.serialize(generateKey(key))));
redisConnection.set(serializer.serialize(generateKey(key)), serializer.serialize(value));
redisConnection.lPush(serializer.serialize(keyListKey), serializer.serialize(generateKey(key)));
} catch (Exception e) {
LOGGER.error("shiro redis cache put exception. ", e);
} finally {
if (null != redisConnection) {
redisConnection.close();
}
}
return result;
}
@Override
public V remove(K key) throws CacheException {
LOGGER.debug("shiro redis cache remove.{} K={}", name, key);
RedisConnection redisConnection = null;
V result = null;
try {
redisConnection = jedisConnectionFactory.getConnection();
result = (V) serializer.deserialize(redisConnection.get(serializer.serialize(generateKey(key))));
redisConnection.expireAt(serializer.serialize(generateKey(key)), 0);
redisConnection.lRem(serializer.serialize(keyListKey), 0, serializer.serialize(key));
} catch (Exception e) {
LOGGER.error("shiro redis cache remove exception. ", e);
} finally {
if (null != redisConnection) {
redisConnection.close();
}
}
return result;
}
@Override
public void clear() throws CacheException {
LOGGER.debug("shiro redis cache clear.{}", name);
RedisConnection redisConnection = null;
try {
redisConnection = jedisConnectionFactory.getConnection();
Long length = redisConnection.lLen(serializer.serialize(keyListKey));
if (0 == length) {
return;
}
List keyList = redisConnection.lRange(serializer.serialize(keyListKey), 0, length - 1);
for (byte[] key : keyList) {
redisConnection.expireAt(key, 0);
}
redisConnection.expireAt(serializer.serialize(keyListKey), 0);
keyList.clear();
} catch (Exception e) {
LOGGER.error("shiro redis cache clear exception.", e);
} finally {
if (null != redisConnection) {
redisConnection.close();
}
}
}
@Override
public int size() {
LOGGER.debug("shiro redis cache size.{}", name);
RedisConnection redisConnection = null;
int length = 0;
try {
redisConnection = jedisConnectionFactory.getConnection();
length = Math.toIntExact(redisConnection.lLen(serializer.serialize(keyListKey)));
} catch (Exception e) {
LOGGER.error("shiro redis cache size exception.", e);
} finally {
if (null != redisConnection) {
redisConnection.close();
}
}
return length;
}
@Override
public Set keys() {
LOGGER.debug("shiro redis cache keys.{}", name);
RedisConnection redisConnection = null;
Set resultSet = null;
try {
redisConnection = jedisConnectionFactory.getConnection();
Long length = redisConnection.lLen(serializer.serialize(keyListKey));
if (0 == length) {
return resultSet;
}
List keyList = redisConnection.lRange(serializer.serialize(keyListKey), 0, length - 1);
resultSet = keyList.stream().map(bytes -> serializer.deserialize(bytes)).collect(Collectors.toSet());
} catch (Exception e) {
LOGGER.error("shiro redis cache keys exception.", e);
} finally {
if (null != redisConnection) {
redisConnection.close();
}
}
return resultSet;
}
@Override
public Collection values() {
return null;
}
/**
* 重组key
* 区别其他使用环境的key
*
* @param key
* @return
*/
private String generateKey(K key) {
return REDIS_SHIRO_CACHE_KEY_PREFIX + name + "_" + key;
}
}
- 使用
redisTemplate
操作redis,可以参考文档:Spring集成shiro使用redis管理session - 不需要专门为保存key建立一个redis.list,直接使用
redisTemplate.keys(key+"*")
就可以,同样参考文档:Spring集成shiro使用redis管理session
自定义cacheManager
ShiroRedisCacheManager.java
package com.sdhs.mob.common.shiro;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.util.Destroyable;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
/**
* shiro redis 缓存
*
* @author seer
* @date 2018/3/24 11:01
*/
public class ShiroRedisCacheManager implements CacheManager, Destroyable {
private static Logger LOGGER = LogManager.getLogger(ShiroRedisCacheManager.class);
private JedisConnectionFactory jedisConnectionFactory;
public ShiroRedisCacheManager(JedisConnectionFactory jedisConnectionFactory) {
this.jedisConnectionFactory = jedisConnectionFactory;
}
@Override
public Cache getCache(String name) throws CacheException {
LOGGER.debug("shiro redis cache manager get cache. name={} ", name);
return new ShiroRedisCache<>(name,jedisConnectionFactory);
}
@Override
public void destroy() throws Exception {
// TODO seer 2018/3/24 12:43 destory
}
}
shiro启用缓存
spring-shiro.xml
···