redis序列化缓存shiro权限角色

当权限信息存放在数据库中时,对于每次前端的访问请求都需要进行一次数据库查询。特别是在大量使用shiro的jsp标签的场景下,对应前端的一个页面访问请求会同时出现很多的权限查询操作,这对于权限信息变化不是很频繁的场景,每次前端页面访问都进行大量的权限数据库查询是非常不经济的。shiro eache缓存方案有效解决了这个问题,但是多台服务器操作的时候就会产生一个问题,一个用户多次登陆,负载均衡可能把它随机分给集群中的任何一个服务器,那么多次操作后,每台服务器都会缓存一个相同的角色权限,造成内存上的浪费.所以用redis去序列化角色权限,每次都去redis中查询操作,这样是一个有效合理的解决方案
一.shiro缓存机制

在这里插入图片描述
Shiro提供了类似于Spring的Cache抽象,即Shiro本身不实现Cache,但是对Cache进行了又抽象,方便更换不同的底层Cache实现。所以我们如果想要实现redis缓存处理,必须先实现两个抽象接口Cache和CacheManager

二.shiro抽象接口实现

(1)实现Cache参考代码

//定义继承Cache类,去在原先shiro处理缓存的基础上,让其把缓存的权限角色缓存到redis中
public class RedisCache<k,V> implements Cache<k,V> {
    //RedisTemplate是Spring-date的一个核心操作类
    private  RedisTemplate<String,Object> redisTemplate;
    //定义一个构造方法需要把redisTempate接收过来,在Shiro原先提供的缓存增删改查方案上
    //利用redisTempate进行redis数据库储存
    public RedisCache(RedisTemplate<String,Object> redisTemplate){
           this.redisTemplate=redisTemplate;
    }
    //取
    @Override
    public V get(k k) throws CacheException {
        System.out.println("get:key:"+k);
        return (V)redisTemplate.opsForValue().get(k.toString());
    }

    //存
    @Override
    public V put(k k, V v) throws CacheException {
        System.out.println("put:key:"+k+"Value:"+v);
        redisTemplate.opsForValue().set(k.toString(),v);
        return v;
    }
    //删
    @Override
    public V remove(k k) throws CacheException {
        System.out.println("remove:k:"+k);
        //定义一个方法取得要删除key的value
        V v=this.get(k);
        redisTemplate.delete(k.toString());
        return v;
    }

    @Override
    public void clear() throws CacheException {
        System.out.println("*****flushdb****");
        //OpsForValue是execute的封装版,execute可以进行类似原始jedis操作
        redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection redisConnection) throws DataAccessException {
                //清空数据库
                redisConnection.flushDb();
                return true;
            }
        });
    }

    //查询所有数据量
    @Override
    public int size() {
        System.out.println("******size*****");
        return redisTemplate.execute(new RedisCallback<Integer>() {

            @Override
            public Integer doInRedis(RedisConnection redisConnection) throws DataAccessException {
                //keys返回的是集合,再跟上size方法,得到数据的数量
                return redisConnection.keys("*".getBytes()).size();
            }
        });
    }


    //获得所有的key
    @Override
    public Set<k> keys() {
        System.out.println("*******keys******");
        return redisTemplate.execute(new RedisCallback<Set<k>>() {
            @Override
            public Set<k> doInRedis(RedisConnection redisConnection) throws DataAccessException {
                Set<k> set=new HashSet<k>();
                //key从redis数据库中取出以字节数组的形式返回
                Set<byte[]> keys=redisConnection.keys("*".getBytes());
                Iterator<byte[]> iter=keys.iterator();
                while (iter.hasNext()){
                    set.add((k) iter.next());
                }
                return set;
            }
        });
    }

    //获得所有的Value
    @Override
    public Collection<V> values() {
        System.out.println("*****keys******");
        return redisTemplate.execute(new RedisCallback<Set<V>>() {
            @Override
            public Set<V> doInRedis(RedisConnection redisConnection) throws DataAccessException {
                Set<V> set=new HashSet<V>();
                //key从redis数据库中取出以字节数组的形式返回
                Set<byte[]> keys=redisConnection.keys("*".getBytes());
                Iterator<byte[]> iter=keys.iterator();
                while (iter.hasNext()){
                    set.add((V)redisConnection.get(iter.next()));
                }
                return set;
            };
        });
    }
}

(2)实现cacheManager接口

public class RedisCacheMange implements CacheManager {
    private final ConcurrentMap<String,Cache> caches=new ConcurrentHashMap<String, Cache>();
    private RedisTemplate<String,Object> redisTemplate;
    //定义一个方法,让其从外部进行注入redisTemplate
    public void setRedisTemplate(RedisTemplate<String,Object> redisTemplate){
        this.redisTemplate=redisTemplate;
    }
    //CacheManger带的方法,获取cache
    @Override
    public <K, V> Cache<K, V> getCache(String s) throws CacheException {
        //首先通过ConcurrentMap中取得(也就是从电脑缓存中取得)
        Cache<K,V> cache=caches.get(s);
        //如果从电脑中无法取得缓存数据,那就需要从redis数据库中取
        if (cache==null){
            //实例化自定义的RedisCache类,并讲注入的redisTemplate传入进去
            //因为自定义的类继承了Shiro的CRUD所以可以自动从redis数据取
            cache=new RedisCache(this.redisTemplate);
            //如果能从redis数据库取出数据,还需要保存到当前服务器上,也就是保存在ConcurrentMap中
            this.caches.put(s,cache);
        }
        return cache;
    }
}

三.配置spring-shiro文件

bean实现接口类,且需要注入已经配置好的redisTemplate

<!--配置自定义redis缓存机制-->
    <bean id="redisCacheMange" class="cn.travel.Cache.RedisCacheMange">
        <property name="redisTemplate" ref="redisTemplate"/>
    </bean>

在shiroSecurity中注入缓存机制

!--配置安全管理器-->
    <bean id="scurityManage" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--配置你需要使用的Realms-->
        <property name="realm" ref="empRealm"/>
        <!--配置会话管理-->
        <property name="sessionManager" ref="sessionManager"/>
        <!--配置缓存管理-->
        <property name="cacheManager" ref="redisCacheMange"/>
    </bean>
四.测试

在项目登陆后会出现如下
实现类讲权限缓存入redis数据库
在这里插入图片描述
我们进入redis服务器查看这条数据
在这里插入图片描述
在这里插入图片描述

成功!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值