Shiro開發團隊明白在許多應用程序中性能是相當重要的。Caching 是Shiro 中的一個重要功能,以確保安全操做保持儘量的快。java
可是,Shiro並不實現緩存的功能,Shiro 的緩存支持基本上是一個抽象的(包裝)API,它將「坐」在一個基本的緩存機制產品(例 如,Ehcache,OSCache,Terracotta,Coherence,GigaSpaces,JBossCache 等)之上。這容許Shiro終端用戶配置他們喜歡的任何緩存機制。spring
Caching APIapache
Shiro 有三個重要的緩存接口:緩存
1:CacheManager - 負責全部緩存的主要管理組件,它返回Cache 實例安全
2:Cache - 維護key/value 對app
3:CacheManagerAware - 經過想要接收和使用CacheManager 實例的組件來實現框架
CacheManager 返回Cache 實例,各類不一樣的Shiro 組件使用這些Cache 實例來緩存必要的數據。任何實現了CacheManagerAware 的Shiro 組件將會自動地接收一個配置好的CacheManager,該CacheManager 可以用來獲取Cache 實例。性能
Shiro 的SecurityManager 實現及全部AuthorizingRealm實現都實現了CacheManagerAware測試
Shiro 提供了一個個當即可用的EhCacheManager 實現this
Caching 配置
經過在SecurityManager上設置了CacheManger,它反過來也會將它設置到實現了CacheManagerAware 的各類不一樣的Realm 上,示例以下:
spring-shiro.xml配置
<!-- 用戶受權信息Cache, 採用EhCache -->
<bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:spring/ehcache-shiro.xml" />
</bean>
ehcache-shiro.xml
<ehcache updateCheck="false" name="shiroCache">
<diskStore path="java.io.tmpdir" />
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="false"
diskPersistent="true" diskExpiryThreadIntervalSeconds="120" />
<cache name="shiro-activeSessionCache" maxElementsInMemory="10000"
eternal="true" timeToLiveSeconds="0" timeToIdleSeconds="0"
diskPersistent="true" overflowToDisk="false"
diskExpiryThreadIntervalSeconds="600">
</cache>
</ehcache>
name:緩存名稱。
maxElementsInMemory:緩存最大個數。
eternal:對象是否永久有效,一但設置了,timeout將不起做用。
timeToIdleSeconds:設置對象在失效前的容許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。
timeToLiveSeconds:設置對象在失效前容許存活時間(單位:秒)。最大時間介於建立時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每一個Cache都應該有本身的一個緩衝區。
maxElementsOnDisk:硬盤最大緩存個數。
diskPersistent:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你能夠設置爲FIFO(先進先出)或是LFU(較少使用)。
clearOnFlush:內存數量最大時是否清除。
包裝使用其餘的Cache框架
能夠經過寫一個類來實現Shiro的CacheManager,在這個類裏面包裝使用任何你想要使用的Cache框架,這裏以使用Srping的緩存框架爲例,參考以下:
public class MyCacheManager implements CacheManager {
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
org.springframework.cache.Cache springCache = cacheManager.getCache(name);
return new SpringCacheWrapper(springCache);
}
class SpringCacheWrapper implements Cache {
private org.springframework.cache.Cache springCache;
SpringCacheWrapper(org.springframework.cache.Cache springCache) {
this.springCache = springCache;
}
public Object get(Object key) throws CacheException {
Object value = springCache.get(key);
if (value instanceof SimpleValueWrapper) {
return ((SimpleValueWrapper) value).get();
}
return value;
}
}
}
緩存數據同步更新的解決方案
使用Shiro的時候,緩存數據最大的問題就在於數據同步更新。
由於Shiro只負責驗證部分,若是應用程序修改了人員的權限,那麼就須要同步更新到Shiro裏面去,也就是要同步Shiro的緩存數據。
一個解決方案就是徹底廢棄Shiro的緩存機制,本身在應用中控制數據的緩存
這裏給出另外一種簡易可行的方案:
1:若是你使用的Spring,並且是自定義的Realm,那麼能夠在你的Realm裏面添加一個方法來刪除該用戶的緩存數據,這樣下次shiro在驗證這個用戶的時候,就會從新去獲取數據,從而實現數據的同步
2:因爲是自定義的Realm,能夠把該對象做爲Spring的bean,注入到你的業務對象中,在須要的時候就能夠調用該方法來刪除shiro的緩存數據了
示例,好比在前面自定義的MyRealm中,添加以下方法,示例以下:
public void removeUserCache(String userId){
SimplePrincipalCollection pc = new SimplePrincipalCollection();
pc.add(userId, super.getName());
super.clearCachedAuthorizationInfo(pc);
}
而後在HelloAnno中進行測試,示例以下:
1:要注入MyRealm,但注意須要使用getter/setter來注入
2:在main方法中,示例以下:
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloAnno t = (HelloAnno)ctx.getBean("helloAnno");
t.login();
t.t();
t.t();
t.getMr().removeUserCache("javass");
t.t();
}