1. 程式人生 > >Apache Shiro(六)——Shiro快取管理

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