Spring集成shiro使用redis做缓存

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

ehcache实现

<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.4.0</version>
</dependency>

《Spring集成shiro使用redis做缓存》 EhCacheManager
《Spring集成shiro使用redis做缓存》 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<K, V> implements Cache<K, V> {
    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<byte[]> 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<byte[]> 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;
    }
}

自定义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 <K, V> Cache<K, V> 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

<bean id="shiroRedisCacheManager" class="com.sdhs.mob.common.shiro.ShiroRedisCacheManager">
        <constructor-arg ref="jedisConnectionFactory"/>
</bean>

<bean id="shiroRealm" class="com.sdhs.mob.back.system.realm.AdminRealm">
        ···
                <!-- 启用缓存 -->
        <property name="cachingEnabled" value="true"/>
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authorizationCachingEnabled" value="true"/>
                <!-- 缓存管理器 -->
        <property name="cacheManager" ref="shiroRedisCacheManager"/>
</bean>

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

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

    原文作者:不敢预言的预言家
    原文地址: https://www.jianshu.com/p/c1c955d8069b
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞