redis序列化缓存shiro权限角色

    xiaoxiao2022-07-14  156

    当权限信息存放在数据库中时,对于每次前端的访问请求都需要进行一次数据库查询。特别是在大量使用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)