Springboot2集成Shiro框架(六)使用MemoryConstrainedCacheManager缓存

1、什么是MemoryConstrainedCacheManager

我们可以查看shiro提供给我们的信息了解这个 MemoryConstrainedCacheManager 的相关信息,在shiro提供的CacheManager接口下,默认提供了缓存抽象类 AbstractCacheManager.class ,还提供了一个实现类 MemoryConstrainedCacheManager 来实现缓存,但是这个缓存默认是关闭的,所以,在之前的篇幅中,我们每次登录,每次访问权限接口都会调用自定义realm中的权限认证和身份认证两个方法。
在这里插入图片描述
Memory Constrained Cache Manager 翻译过来就是保存在内存中的缓存管理器,由于运行在jvm环境下,也可以理解为使用jvm的内存保存数据的工具,适合在单实例使用。

  • 在官方文档上有如下说法
    基于内存的简单{@link CacheManager CacheManager}实现可在生产中使用
    环境。它不会导致内存泄漏,因为它会生成{@link Cache Cache}
    {@link SoftHashMap SoftHashMap}根据运行时环境的内存自动调整大小
    限制和垃圾收集行为。
    虽然创建的{@code Cache}实例是线程安全的,但它们不提供任何企业级功能,例如
    缓存一致性,乐观锁定,故障转移或其他类似功能。有关更多企业功能,请考虑
    使用由企业级缓存产品支持的不同{@code CacheManager}实现(EhCache,
    TerraCotta,Coherence,GigaSpaces等等)

2、为什么要使用缓存

在之前的配置中,并没有使用缓存,我们可以看到每次登录或者访问权限接口时,总会频繁的调用我们自定义realm的身份认证和权限认证的方法,尤其是权限认证!频繁的对数据库进行访问,占用很多数据库资源,这是我们不想看到的,使用缓存可以将一些不会经常变动的值存下来,需要时直接在缓存中取数据对比即可,无需访问数据库,减少数据库资源的占用,提高系统性能等!

3、如何使用

  1. ShiroConfig类中添加缓存管理器
    /**
     * 缓存管理器
     * @return
     */
    @Bean
    public CacheManager cacheManager() {
        MemoryConstrainedCacheManager mccm = new MemoryConstrainedCacheManager();
        return mccm;
    }
  1. 授权管理器交给securityManager
    /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myShiroRealm());
        securityManager.setRememberMeManager(rememberMeManager());
        securityManager.setCacheManager(cacheManager());//配置缓存管理器
        return securityManager;
    }
  1. 自定义realm中开启缓存
    /**
     * 自定义身份认证 realm;
     * <p>
     * 必须写这个类,并加上 @Bean 注解,目的是注入 MyShiroRealm, 否则会影响 MyShiroRealm类 中其他类的依赖注入
     */
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        // 设置密码比较器
        myShiroRealm.setCredentialsMatcher(CredentialsMatcher());
        // 启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
        myShiroRealm.setAuthenticationCachingEnabled(true);
        // 启用授权缓存,即缓存AuthorizationInfo信息,默认false,一旦配置了缓存管理器,授权缓存默认开启
        myShiroRealm.setAuthorizationCachingEnabled(true);
        
        return myShiroRealm;
    }

4、如何清理缓存

4.1、调用logout方法

我们发现调用logout方法可以同时清除两种缓存,但是此方法只能清除当前用户,并且会强制退出,实用性不强。

	Subject subject = SecurityUtils.getSubject();
	// 登出
	subject.logout();

4.2、主动清理缓存

4.2.1、部分新增缓存代码

可以看出,我们使用的缓存保存的key是采用 principals 属性,因此我们清除的时候只需要传入用户名即可!

//缓存代码
class AuthorizingRealm{
	.........................
        if (info == null) {
            // Call template method if the info was not found in a cache
            info = doGetAuthorizationInfo(principals);
            // If the info is not null and the cache has been created, then cache the authorization info.
            if (info != null && cache != null) {
                if (log.isTraceEnabled()) {
                    log.trace("Caching authorization info for principals: [" + principals + "].");
                }
                Object key = getAuthorizationCacheKey(principals);
                cache.put(key, info);
            }
        }

4.2.2、配置主动缓存清理

  1. MyShiroRealm 类中新增下列方法

    /**
     * 重写方法,清除当前用户的的 授权缓存
     * @param principals
     */
    public void clearCachedAuthorizationInfo() {
        super.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    /**
     * 重写方法,清除当前用户的 认证缓存
     * @param principals
     */
    public void clearCachedAuthenticationInfo() {
        super.clearCachedAuthenticationInfo(SecurityUtils.getSubject().getPrincipals());
    }
    /**
     * 清除某个用户认证和授权缓存
     */
    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    /**
     * 自定义方法:清除所有 授权缓存
     */
    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    /**
     * 自定义方法:清除所有 认证缓存
     */
    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    /**
     * 自定义方法:清除所有的  认证缓存  和 授权缓存
     */
    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }
    
    
  1. ShiroController 新增接口
    @RequestMapping("/clear")
    public ReturnMap clear() {
        RealmSecurityManager rsm = (RealmSecurityManager)SecurityUtils.getSecurityManager();  
        MyShiroRealm realm = (MyShiroRealm)rsm.getRealms().iterator().next(); 
        realm.clearCachedAuthenticationInfo();
        realm.clearCachedAuthorizationInfo();
        System.out.println("清除成功");
        return new ReturnMap().success().data("清除成功");
    }
  1. 页面新增清除接口按钮在这里插入图片描述

5、测试

  1. 我们登录了3次,并且访问了很多次权限接口的情况下,下图红色部分为进入认证器的次数,也可以理解为访问数据库次数,只有两次,测试成功!在这里插入图片描述
  2. 接着上面的测试继续,我们点击clear接口,并且再进行登录和接口访问,可以看到,每次清除完缓存之后,下次访问必定会再次访问数据库,把数据写入缓存,清除缓存测试成功!
  3. 在这里插入图片描述

4、源码

  • 需要源码可以点击这里获取!
  • 另,非常感谢凌寒11童鞋分享的清除缓存代码!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章