Spring集成shiro使用redis做缓存

shiro提供基于ehcache的缓存实现,参照相关的实现类,我们可以自定义基于redis的缓存实现。

ehcache实现



    org.apache.shiro
    shiro-ehcache
    1.4.0

Spring集成shiro使用redis做缓存_第1张图片
EhCacheManager
Spring集成shiro使用redis做缓存_第2张图片
EhCache

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


        



        ···
                
        
        
        
                
        

关于缓存参数启动参数的设置和区别可以参照:shiro Realm 缓存默认值

如遇java.io.NotSerializableException: org.apache.shiro.util.SimpleByteSource异常,参照:[Shiro入门] (二)缓存管理器SimpleByteSource序列化问题

你可能感兴趣的:(Spring集成shiro使用redis做缓存)