Apache Shiro(六)——Shiro快取管理
一、概述
CacheManagerAware 介面
Shiro 內部相應的元件(DefaultSecurityManager)會自動檢測相應的物件(如Realm)是否實現了CacheManagerAware 並自動注入相應的CacheManager。
Realm 快取
Shiro 提供了 CachingRealm,其實現了CacheManagerAware 介面,提供了快取的一些基礎實現。
AuthenticatingRealm 及 AuthorizingRealm 也分別提供了對AuthenticationInfo 和 AuthorizationInfo 資訊的快取。
Session 快取
如 SecurityManager 實現了 SessionSecurityManager,其會判斷 SessionManager 是否實現了CacheManagerAware 介面,如果實現了會把CacheManager 設定給它。
SessionManager 也會判斷相應的 SessionDAO(如繼承自CachingSessionDAO)是否實現了CacheManagerAware,如果實現了會把 CacheManager設定給它。
設定了快取的 SessionManager,查詢時會先查快取,如果找不到才查資料庫。
二、整合redis,實現shiro的CacheManager
Shiro預設整合了EhCache,來實現快取,如果我們想用redis替換EhCache來實現快取怎麼做了?我們可以從Shiro的原始碼來找到一些端倪。我們可以模擬EhCacheManager的實現方式,EhCacheManager類定義如下:
public class EhCacheManager implements CacheManager, Initializable, Destroyable {
}
我們從上面的程式碼可以看到,最終要的是實現了CacheManager介面,該介面很簡單,只有一個方法:
public interface CacheManager { /** * Acquires the cache with the specified <code>name</code>. If a cache does not yet exist with that name, a new one * will be created with that name and returned. * * @param name the name of the cache to acquire. * @return the Cache with the given name * @throws CacheException if there is an error acquiring the Cache instance. */ public <K, V> Cache<K, V> getCache(String name) throws CacheException; }
從上面的註釋中,我們可以發現,這個介面需要一個Cache,通過name來獲取Cache,首先,我們來實現CacheManager這個介面:
@Service
public class RedisCacheManager implements CacheManager {
@Autowired
private RedisTemplate redisTemplate; // RedisTemplate,如果不明白怎麼使用的,請參考http://blog.csdn.net/liuchuanhong1/article/details/54601037
@Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
System.out.println("name:"+name);
return new RedisCache<K, V>(120, redisTemplate);// 為了簡化程式碼的編寫,此處直接new一個Cache
}
}
下面,我們來實現Cache類:
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;
public class RedisCache<K, V> implements Cache<K, V> {
private long expireTime = 120;// 快取的超時時間,單位為s
private RedisTemplate<K, V> redisTemplate;// 通過構造方法注入該物件
public RedisCache() {
super();
}
public RedisCache(long expireTime, RedisTemplate<K, V> redisTemplate) {
super();
this.expireTime = expireTime;
this.redisTemplate = redisTemplate;
}
/**
* 通過key來獲取對應的快取物件
* 通過原始碼我們可以發現,shiro需要的key的型別為Object,V的型別為AuthorizationInfo物件
*/
@Override
public V get(K key) throws CacheException {
return redisTemplate.opsForValue().get(key);
}
/**
* 將許可權資訊加入快取中
*/
@Override
public V put(K key, V value) throws CacheException {
redisTemplate.opsForValue().set(key, value, this.expireTime, TimeUnit.SECONDS);
return value;
}
/**
* 將許可權資訊從快取中刪除
*/
@Override
public V remove(K key) throws CacheException {
V v = redisTemplate.opsForValue().get(key);
redisTemplate.opsForValue().getOperations().delete(key);
return v;
}
@Override
public void clear() throws CacheException {
}
@Override
public int size() {
return 0;
}
@Override
public Set<K> keys() {
return null;
}
@Override
public Collection<V> values() {
return null;
}
}
這兩步完成之後,就是需要將原來的EhCacheManager的配置換成RedisCacheManager了。
@Bean
public DefaultWebSessionManager configWebSessionManager(){
DefaultWebSessionManager manager = new DefaultWebSessionManager();
manager.setCacheManager(cacheManager);// 換成Redis的快取管理器
manager.setSessionDAO(sessionDao);
manager.setDeleteInvalidSessions(true);
manager.setGlobalSessionTimeout(sessionDao.getExpireTime());
manager.setSessionValidationSchedulerEnabled(true);
return manager;
}
通過上面的幾步,我們就實現了用Redis來快取Shiro的許可權等相關資訊。
三、相關連線
springboot②最正確的整合shiro並使用ehcache快取
spring boot整合redis,實現shiro的CacheManager