上一章我們講解了如何擴展集中式的session管理方便我們集羣的應用項目,無須再使用複製session的方式來完善用戶體系;下面我主要分享如何擴展shiro裏的緩存實現,
大家都知道有點規模的項目都必須會使用緩存這個好東西,所以一個好的框架基本都會包含一套多級緩存的機制,例如spring,hibernate等也會有自己一套,象第三方的oscache,ehcache等等;
不扯沒營養的話了,還是說回shiro的緩存,shiro的緩存比較簡單,我們可以看看shiro定義的cache接口源碼
package org.apache.shiro.cache;
import java.util.Collection;
import java.util.Set;
// Referenced classes of package org.apache.shiro.cache:
// CacheException
public interface Cache
{
public abstract Object get(Object obj)
throws CacheException;
public abstract Object put(Object obj, Object obj1)
throws CacheException;
public abstract Object remove(Object obj)
throws CacheException;
public abstract void clear()
throws CacheException;
public abstract int size();
public abstract Set keys();
public abstract Collection values();
}
很明顯看到跟我們普通的cache差不多,也是CRUD等等方法,然後看看有shiro寫的有哪些實現類
一個是org.apache.shiro.cache.ehcache.EhCache
一個是org.apache.shiro.cache.MapCache
然後看着名字我們就大概知道一個是基於encache框架來作爲實現類基礎,一個是以本地map來裝載數據到內存達到緩存的效果,這裏類的源碼可以自己看看,比較簡單,shiro入門後的都能看懂,但是這些實現類都不適合我用,我想要的是用memcached或是redis作爲數據的緩存容器
下面我就來分享下自己的實現流程
上面我們已經看過shiro的cache接口,下面我們就實現一個序列化的cache實現類
/**
*
* 緩存實現類,實現序列 接口方便對象存儲於第三方容器(Map存放鍵值對)
*
*
*/
@SuppressWarnings("serial")
public class SimpleMapCache implements Cache<Object, Object>, Serializable {
private final Map<Object, Object> attributes;
private final String name;
public SimpleMapCache(String name, Map<Object, Object> backingMap) {
if (name == null)
throw new IllegalArgumentException("Cache name cannot be null.");
if (backingMap == null) {
throw new IllegalArgumentException("Backing map cannot be null.");
} else {
this.name = name;
attributes = backingMap;
}
}
public Object get(Object key) throws CacheException {
return attributes.get(key);
}
public Object put(Object key, Object value) throws CacheException {
return attributes.put(key, value);
}
public Object remove(Object key) throws CacheException {
return attributes.remove(key);
}
public void clear() throws CacheException {
attributes.clear();
}
public int size() {
return attributes.size();
}
public Set<Object> keys() {
Set<Object> keys = attributes.keySet();
if (!keys.isEmpty())
return Collections.unmodifiableSet(keys);
else
return Collections.emptySet();
}
public Collection<Object> values() {
Collection<Object> values = attributes.values();
if (!CollectionUtils.isEmpty(values))
return Collections.unmodifiableCollection(values);
else
return Collections.emptySet();
}
public String toString() {
return (new StringBuilder("SimpleMapCache '")).append(name).append("' (").append(attributes.size()).append(
" entries)").toString();
}
}
其實上面的cache實現我直接用mapcache實現類的源碼然後增加實現序列化的接口,比較方便
然後我們把自己的資源搞到一個map裏,然後new SimpleMapCache(Map)就生成一個緩存堆,最後添加到緩存管理器裏面即可
下面我們看看如何實現緩存管理器
所以我們先實現一個自定義的緩存管理器接口方便我們操作每一個緩存堆
/**
*
* 緩存管理器接口
*
* @author shadow
*
*/
public interface SimpleCacheManager {
/**
* 新增緩存堆到管理器
*
* @param name
* @param cache
*/
public abstract void createCache(String name, Cache<Object, Object> cache) throws CacheException;
/**
* 獲取緩存堆
*
* @param name
* @return
* @throws CacheException
*/
public abstract Cache<Object, Object> getCache(String name) throws CacheException;
/**
* 移除緩存堆
*
* @param name
* @throws CacheException
*/
public abstract void removeCache(String name) throws CacheException;
/**
* 更新緩存堆
*
* @param name
* @param cache
*/
public abstract void updateCahce(String name, Cache<Object, Object> cache) throws CacheException;
/**
* 註銷管理器
*/
public abstract void destroy() throws CacheException;
}
接口已經定義好,我們就寫一個實現類完成我們的邏輯,並且這個邏輯是把緩存堆對象放到memcached裏面
/**
*
* 緩存管理器實現類
*
* @author shadow
*
*/
public class SimpleCacheManagerImpl implements SimpleCacheManager {
private MemcachedClient memcachedClient;
public SimpleCacheManagerImpl(MemcachedClient memcachedClient) {
if (memcachedClient == null) {
throw new RuntimeException("必須存在memcached客戶端實例");
}
this.memcachedClient = memcachedClient;
}
@Override
public void createCache(String name, Cache<Object, Object> cache) throws CacheException {
try {
memcachedClient.set(name, 0, cache);
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public Cache<Object, Object> getCache(String name) throws CacheException {
try {
return memcachedClient.get(name);
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public void removeCache(String name) throws CacheException {
try {
memcachedClient.delete(name);
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public void updateCahce(String name, Cache<Object, Object> cache) throws CacheException {
try {
memcachedClient.replace(name, 0, cache);
} catch (Exception e) {
throw new CacheException(e);
}
}
@Override
public void destroy() throws CacheException {
try {
memcachedClient.shutdown();
} catch (Exception e) {
throw new CacheException(e);
}
}
}
然後我們就開始把這自定義的管理器接入到shiro的緩存管理器
/**
*
* 安全框架緩存管理器實現類
*
* @author shadow
*
*/
public class ShiroCacheManager implements CacheManager, Destroyable {
private SimpleCacheManager simpleCacheManager;
@Override
public Cache<Object, Object> getCache(String name) throws CacheException {
return simpleCacheManager.getCache(name);
}
@Override
public void destroy() throws Exception {
simpleCacheManager.destroy();
}
public SimpleCacheManager getSimpleCacheManager() {
return simpleCacheManager;
}
public void setSimpleCacheManager(SimpleCacheManager simpleCacheManager) {
this.simpleCacheManager = simpleCacheManager;
}
}
最後配置下這個shiro的管理器實現類注入到需要的地方即可
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="sessionManager" ref="sessionManager" />
<property name="cacheManager" ref="shiroCacheManager" />
<property name="realm" ref="simpleUserRealm" />
</bean>
<!-- 安全框架緩存管理器 -->
<bean id="shiroCacheManager" class="com.silvery.security.shiro.cache.ShiroCacheManager">
<property name="simpleCacheManager" ref="simpleCacheManager" />
</bean>
<!-- 擴展緩存管理器 -->
<bean id="simpleCacheManager"
class="com.silvery.security.shiro.cache.extend.impl.SimpleCacheManagerImpl">
<constructor-arg ref="memcachedClient" />
</bean>
配置好了之後,我們在需要地方把實例化的SimpeMapCache添加到我們的自己的管理器裏面即可...
這個章節已經講完了,謝謝大家的支持
歡迎拍磚...