https://blog.csdn.net/weixin_34137799/article/details/88068777
https://blog.csdn.net/coolwindd/article/details/84862184
缓存-Caching - 图1

Cache 接口

Shiro 提供的 Cache 接口,该接口用于自定义缓存的设置和获取等操作,我们使用的时候需要实现它来完成缓存操作,例如使用 Redis 来管理缓存。

  1. public interface Cache<K, V> {
  2. //根据Key获取缓存中的值
  3. public V get(K key) throws CacheException;
  4. //往缓存中放入key-value,返回缓存中之前的值
  5. public V put(K key, V value) throws CacheException;
  6. //移除缓存中key对应的值,返回该值
  7. public V remove(K key) throws CacheException;
  8. //清空整个缓存
  9. public void clear() throws CacheException;
  10. //返回缓存大小
  11. public int size();
  12. //获取缓存中所有的key
  13. public Set<K> keys();
  14. //获取缓存中所有的value
  15. public Collection<V> values();
  16. }

CacheManager 接口

Shiro 提供的 CacheManager 接口,该接口用于注入 securityManager 让 Shiro 来管理缓存处理。

  1. public interface CacheManager {
  2. //根据缓存名字获取一个Cache
  3. <K, V> Cache<K, V> getCache(String var1) throws CacheException;
  4. }

缓存管理器

缓存管理器的配置很简单,简单来说步骤是:在 SecurityManager 中注入 CacheManager 即可。

使用缓存可以避免需要授权信息时频繁的调用数据库查询的问题。我们可以使用 ehcache、Redis 自定义 CacheManager 的实现。

需要注意的是,我们使用的是 shiro 框架提供的缓存管理器 UserRealm里注入的 SysUserService 等service,需要延迟注入,即都要添加@Lazy注解(如果不加需要自己延迟注入),否则会导致该 service 里的 @Cacheable 缓存注解、@Transactional 事务注解等失效。

1. EhCache 实现缓存管理器

  1. 导入依赖 pom.xml

    1. <!-- 使用 ehcache 做缓存 -->
    2. <dependency>
    3. <groupId>org.apache.shiro</groupId>
    4. <artifactId>shiro-ehcache</artifactId>
    5. <version>1.3.2</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>net.sf.ehcache</groupId>
    9. <artifactId>ehcache-core</artifactId>
    10. <version>2.6.9</version>
    11. </dependency>
  2. 添加配置文件 ehcache.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <ehcache updateCheck="false" dynamicConfig="false">
    3. <diskStore path="java.io.tmpdir"/>
    4. <cache name="users"
    5. timeToLiveSeconds="300"
    6. maxEntriesLocalHeap="1000"/>
    7. <!--
    8. name:缓存名称。
    9. maxElementsInMemory:缓存最大个数。
    10. eternal:对象是否永久有效,一但设置了,timeout将不起作用。
    11. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
    12. timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
    13. overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
    14. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
    15. maxElementsOnDisk:硬盘最大缓存个数。
    16. diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
    17. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
    18. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
    19. clearOnFlush:内存数量最大时是否清除。
    20. -->
    21. <defaultCache name="defaultCache"
    22. maxElementsInMemory="10000"
    23. eternal="false"
    24. timeToIdleSeconds="120"
    25. timeToLiveSeconds="120"
    26. overflowToDisk="false"
    27. maxElementsOnDisk="100000"
    28. diskPersistent="false"
    29. diskExpiryThreadIntervalSeconds="120"
    30. memoryStoreEvictionPolicy="LRU"/>
    31. </ehcache>
  3. 添加配置 ShiroConfig.java ```java @Bean public EhCacheManager ehCacheManager() { EhCacheManager cacheManager = new EhCacheManager(); cacheManager.setCacheManagerConfigFile(“classpath:ehcache.xml”); return cacheManager; }

@Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 管理 realm securityManager.setRealm(userRealm()); // 缓存管理器 securityManager.setCacheManager(ehCacheManager()); return securityManager; }

<a name="HzhF1"></a>
## 2. Shiro-Redis 实现缓存管理器
shiro-redis 依赖包为我们试了 Cache 和 CacheManager 接口

1. 导入依赖,这里使用 shiro-redis 简化配置
```xml
<!-- shiro-redis -->
<dependency>
  <groupId>org.crazycake</groupId>
  <artifactId>shiro-redis</artifactId>
  <version>3.1.0</version>
  <exclusions>
    <exclusion>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>
  1. 添加配置 ```java /**
    • Redis 管理 *
    • @return */ @Bean public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(“127.0.0.1”); redisManager.setPort(6379); redisManager.setPassword(“123456”); return redisManager; }

/**

  • Redis 缓存管理器 *
  • @return */ @Bean public RedisCacheManager redisCacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); //redis中针对不同用户缓存 redisCacheManager.setPrincipalIdFieldName(“username”); //用户权限信息缓存时间 redisCacheManager.setExpire(200000); return redisCacheManager; } ```

3. 内存缓存管理器

这种方式配置比较简单,但无法保证缓存一致性、乐观锁定等功能,实际开发中不推荐。

@Bean
public CacheManager cacheManager() {
    log.info("配置缓存管理器");
    return new MemoryConstrainedCacheManager();
}

@Bean
public DefaultWebSecurityManager securityManager() {
    log.info("security manager");
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
    // 管理 realm
    securityManager.setRealm(userRealm());
    // 缓存管理器
    securityManager.setCacheManager(cacheManager());
    return securityManager;
}