2021年你还不会Shiro?----10.使用redis实现Shiro的缓存

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 上一篇文章已经总结了使用ehCache来实现Shiro的缓存管理,步骤也很简单,引入依赖后,直接开启Realm的缓存管理器即可。如果使用Redis来实现缓存管理其实也是一样的,我们也是需要引入redis的依赖,然后开启缓存传入自定义的redis的缓存管理器就行。区别是我们需要为自定义的redis缓存管理器提供自定义的缓存管理类。这个缓存管理类中需要使用到redisTemplate模板,这个模板我们也是需要自己定义。

前言:

上一篇文章已经总结了使用ehCache来实现Shiro的缓存管理,步骤也很简单,引入依赖后,直接开启Realm的缓存管理器即可。如果使用Redis来实现缓存管理其实也是一样的,我们也是需要引入redis的依赖,然后开启缓存传入自定义的redis的缓存管理器就行。区别是我们需要为自定义的redis缓存管理器提供自定义的缓存管理类。这个缓存管理类中需要使用到redisTemplate模板,这个模板我们也是需要自己定义。


一.实现过程



主要过程就是导入依赖、提供自定义缓存管理器、提供缓存管理类、开启缓存传入自定义缓存管理器即可。


1.导入redis依赖。


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>


2.提供自定义缓存管理器 MyRedisCacheManager


我们使用EhCacheManager缓存时发现EhCacheManager实现了CacheManager这个接口,所以我们自定义缓存管理器时也需要实现该接口,这个接口只有一个方法,就是用来获取缓存管理类,实现如下:

public class MyRedisCacheManager implements CacheManager {
    /**
    *   只要加入了缓存管理器,配置了缓存管理类,系统就会默认在查询完认证和授权后将信息放入到缓存中
    *   且下次需要认证和授权时,都是优先去查询缓存中的内容,查询不到,才会去查询数据库,这里也验证了
    *   这一点,与之前的画的加入缓存后的授权信息的获取图是一样的。
     */
    @Override
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
        System.out.println("进入到了自定义缓存管理器,传入参数cacheName:"+ cacheName);
        return new RedisCache<K,V>(cacheName);
    }
}


3.设计自己的缓存管理类


根据上方的代码我们可以看到,所有的缓存管理类的实例都应该是Cache的实现类。所以我们自己定义redis的缓存管理类应该也必须去实现这个Cache类。实现如下:

@NoArgsConstructor
public class RedisCache<k,v> implements Cache<k,v> {
    private String cacheName;
    @Autowired
    public  RedisTemplate redisTemplate;
    public static RedisTemplate redisTemplateSelf;
    @PostConstruct
    public void getRedisTemplate(){
        this.redisTemplateSelf = redisTemplate;
    }
    public RedisCache (String cacheName1){
        this.cacheName = cacheName1;
    }
    @Override
    public v get(k k) throws CacheException {
        System.out.println(cacheName+":获取缓存方法,传入参数:" + k+",此时的redisTemplate:"+redisTemplateSelf);
        //获取缓存中数据时一定要为k加toStirng方法,否则会报错序列化的错
        if(null != redisTemplateSelf.opsForHash().get(cacheName.toString(),k.toString())){
            return (v)redisTemplateSelf.opsForHash().get(cacheName.toString(),k.toString());
        }
        return null;
    }
    @Override
    public v put(k k, v v) throws CacheException {
        System.out.println("加入缓存方法,传入参数 K:" + k+",V:"+v);
        //放入redis中的值,一定要是序列化的对象
        redisTemplateSelf.opsForHash().put(cacheName.toString(),k.toString(),v);
        return null;
    }
    @Override
    public v remove(k k) throws CacheException {
        System.out.println("调用了remove方法,传入参数:"+k.toString());
        redisTemplateSelf.opsForHash().delete(cacheName.toString(),k.toString());
        return null;
    }
    @Override
    public void clear() throws CacheException {
        System.out.println("调用了clear方法");
        redisTemplateSelf.delete(cacheName);
    }
    @Override
    public int size() {
        return redisTemplateSelf.opsForHash().size(cacheName).intValue();
    }
    @Override
    public Set<k> keys() {
        return redisTemplateSelf.opsForHash().keys(cacheName);
    }
    @Override
    public Collection<v> values() {
        return redisTemplateSelf.opsForHash().values(cacheName);
    }
}


这个类里我们实现了设置缓存、获取缓存、移除缓存、情况缓存等方法。

其中我们开启缓存后,用户登录成功就会将缓存放入到redis中,使用退出功能,就会清楚当前登录的缓存信息,授权信息也是一样,只要使用退出功能就会清空当前的缓存信息。但是这里并没有设计过期时间的处理。所以真实场景下,我们还需要考虑过期时间的设置。这里显然我们用到了RedisTemplate模板,这个模板我们一般也是自己定义,不过也可以直接使用SpringBoot默认提供的。这里我们采用自己定义RedisTemplate的方式。


4.自定义RedisTemplate注入到Spring容器中


 //注入自定义的RedisTemplate
    @Bean
    public RedisTemplate getRedisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(connectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    //注入Shiro的缓存对象
    @Bean
    public RedisCache getRedisCache(){
        RedisCache redisCache = new RedisCache();
        return  redisCache;
    }


5.Realm中开启缓存管理


经过以上的过程,必要的过程以及完成了,可以在Realm中开启缓存管理器了,如下:

@Bean
    public FirstRealm getRealm(){
        FirstRealm firstRealm = new FirstRealm();
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(2048);
//        下面的写法也是正常的,不过现在都是使用上面的写法,下面的写法已经是不推荐使用的了。
//        Md5CredentialsMatcher md5CredentialsMatcher = new Md5CredentialsMatcher();
//        md5CredentialsMatcher.setHashIterations(2048);
        firstRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        //开启缓存
//        firstRealm.setCachingEnabled(true);//开启全局的缓存管理
        firstRealm.setAuthenticationCachingEnabled(true);//开启认证缓存
//        firstRealm.setAuthorizationCachingEnabled(true);//开启授权缓存
        //缓存名称很有必要设置,因为若是只使用k,v的形式设置redis缓存,认证和授权默认的k都是用户名,所以我们
        //需要使用k,map的形式存储,k就可以是这个设置的缓存名称,缓存管理器中传入的k就是这个值。
        firstRealm.setAuthenticationCacheName("authenticationCache");//设置缓存名称--认证
        firstRealm.setAuthorizationCacheName("authorizationCache");//设置缓存名称--授权
        firstRealm.setCacheManager(new MyRedisCacheManager());
        return firstRealm;
    }


6.测试缓存是否有效


我们已经完成了使用Redis进行Shiro的缓存管理的所有功能。下面就来测试下上面的过程是否有效。


20210401104118382.gif


经过多次刷新页面发现,每次都是去缓存中拿数据,而不是去走认证方法,这样我们的缓存实现就成功了。但是上方的redisTemplate虽然是我们定义的,但是真实项目中一般不这么用,都会定义自己的Redis工具类。


shiro留下的坑,盐必须序列化


在Realm中定义缓存管理器与在安全管理器中定义缓存管理器有区别吗?


没什么区别,在自定义realm中设置缓存管理,与安全管理器中设置缓存,realm都能正常拥有缓存。不过不同的是若是在安全管理器中设置缓存,安全管理器拥有了缓存,realm同时也会有缓存,若是在realm设置,安全管理器则不会有缓存。但是事实上安全管理器的缓存管理也是为了realm服务的,除了realm需要缓存管理,其他也没有了。所以即使这设置的范围不同,但是效果都是一样的。在我看来,设置在realm中更符合逻辑。符合谁需要设置给谁的原则。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3天前
|
缓存 NoSQL Java
使用Redis进行Java缓存策略设计
【4月更文挑战第16天】在高并发Java应用中,Redis作为缓存中间件提升性能。本文探讨如何使用Redis设计缓存策略。Redis是开源内存数据结构存储系统,支持多种数据结构。Java中常用Redis客户端有Jedis和Lettuce。缓存设计遵循一致性、失效、雪崩、穿透和预热原则。常见缓存模式包括Cache-Aside、Read-Through、Write-Through和Write-Behind。示例展示了使用Jedis实现Cache-Aside模式。优化策略包括分布式锁、缓存预热、随机过期时间、限流和降级,以应对缓存挑战。
|
11天前
|
存储 缓存 NoSQL
Java手撸一个缓存类似Redis
`LocalExpiringCache`是Java实现的一个本地缓存类,使用ConcurrentHashMap存储键值对,并通过ScheduledExecutorService定时清理过期的缓存项。类中包含`put`、`get`、`remove`等方法操作缓存,并有`clearCache`方法来清除过期的缓存条目。初始化时,会注册一个定时任务,每500毫秒检查并清理一次过期缓存。单例模式确保了类的唯一实例。
11 0
|
1月前
|
缓存 NoSQL Java
spring cache整合redis实现springboot项目中的缓存功能
spring cache整合redis实现springboot项目中的缓存功能
45 1
|
1月前
|
缓存 NoSQL 数据库
[Redis]——数据一致性,先操作数据库,还是先更新缓存?
[Redis]——数据一致性,先操作数据库,还是先更新缓存?
|
1月前
|
缓存 NoSQL Java
【九】springboot整合redis实现启动服务时热点数据保存在全局和缓存
【九】springboot整合redis实现启动服务时热点数据保存在全局和缓存
40 0
|
5月前
|
缓存 NoSQL 安全
Redis缓存雪崩、击穿、穿透解释及解决方法,缓存预热,布隆过滤器 ,互斥锁
Redis缓存雪崩、击穿、穿透解释及解决方法,缓存预热,布隆过滤器 ,互斥锁
183 5
|
6月前
|
缓存 NoSQL 数据库
Redis学习笔记-如何应对缓存雪崩、击穿、穿透
Redis学习笔记-如何应对缓存雪崩、击穿、穿透
38 0
|
存储 缓存 NoSQL
Redis --- 缓存雪崩、击穿、穿透与数据库缓存双一致性
Redis --- 缓存雪崩、击穿、穿透与数据库缓存双一致性
Redis --- 缓存雪崩、击穿、穿透与数据库缓存双一致性
|
缓存 NoSQL 关系型数据库
Redis缓存雪崩、击穿、穿透、到底是什么?
今日目标 能够掌握Redis缓存雪崩概念及解决方案 能够掌握Redis缓存击穿概念及解决方案 能够掌握Redis缓存穿透概念及解决方案
|
缓存 NoSQL Redis
Redis 缓存雪崩、击穿、穿透
什么是缓存雪崩、击穿、穿透
1416 0

热门文章

最新文章