shiro安全框架擴充套件教程--如何擴充套件實現我們的快取機制(第三方容器redis,memcached)

Joker_Ye發表於2016-07-14

大家都知道有點規模的專案都必須會使用快取這個好東西,所以一個好的框架基本都會包含一套多級快取的機制,例如spring,hibernate等也會有自己一套,象第三方的oscache,ehcache等等;


不扯沒營養的話了,還是說回shiro的快取,shiro的快取比較簡單,我們可以看看shiro定義的cache介面原始碼


[html] view plain copy
  1. package org.apache.shiro.cache;  
  2.   
  3. import java.util.Collection;  
  4. import java.util.Set;  
  5.   
  6. // Referenced classes of package org.apache.shiro.cache:  
  7. //            CacheException  
  8.   
  9. public interface Cache  
  10. {  
  11.   
  12.     public abstract Object get(Object obj)  
  13.         throws CacheException;  
  14.   
  15.     public abstract Object put(Object obj, Object obj1)  
  16.         throws CacheException;  
  17.   
  18.     public abstract Object remove(Object obj)  
  19.         throws CacheException;  
  20.   
  21.     public abstract void clear()  
  22.         throws CacheException;  
  23.   
  24.     public abstract int size();  
  25.   
  26.     public abstract Set keys();  
  27.   
  28.     public abstract Collection values();  
  29. }  

很明顯看到跟我們普通的cache差不多,也是CRUD等等方法,然後看看有shiro寫的有哪些實現類

一個是org.apache.shiro.cache.ehcache.EhCache

一個是org.apache.shiro.cache.MapCache

然後看著名字我們就大概知道一個是基於encache框架來作為實現類基礎,一個是以本地map來裝載資料到記憶體達到快取的效果,這裡類的原始碼可以自己看看,比較簡單,shiro入門後的都能看懂,但是這些實現類都不適合我用,我想要的是用memcached或是redis作為資料的快取容器


下面我就來分享下自己的實現流程



上面我們已經看過shiro的cache介面,下面我們就實現一個序列化的cache實現類


[html] view plain copy
  1. /**  
  2.  *   
  3.  * 快取實現類,實現序列 介面方便物件儲存於第三方容器(Map存放鍵值對)  
  4.  *   
  5.  *   
  6.  */  
  7. @SuppressWarnings("serial")  
  8. public class SimpleMapCache implements Cache<Object, Object>, Serializable {  
  9.   
  10.     private final Map<Object, Object> attributes;  
  11.     private final String name;  
  12.   
  13.     public SimpleMapCache(String name, Map<Object, Object> backingMap) {  
  14.         if (name == null)  
  15.             throw new IllegalArgumentException("Cache name cannot be null.");  
  16.         if (backingMap == null) {  
  17.             throw new IllegalArgumentException("Backing map cannot be null.");  
  18.         } else {  
  19.             this.name = name;  
  20.             attributes = backingMap;  
  21.         }  
  22.     }  
  23.   
  24.     public Object get(Object key) throws CacheException {  
  25.         return attributes.get(key);  
  26.     }  
  27.   
  28.     public Object put(Object key, Object value) throws CacheException {  
  29.         return attributes.put(key, value);  
  30.     }  
  31.   
  32.     public Object remove(Object key) throws CacheException {  
  33.         return attributes.remove(key);  
  34.     }  
  35.   
  36.     public void clear() throws CacheException {  
  37.         attributes.clear();  
  38.     }  
  39.   
  40.     public int size() {  
  41.         return attributes.size();  
  42.     }  
  43.   
  44.     public Set<Object> keys() {  
  45.         Set<Object> keys = attributes.keySet();  
  46.         if (!keys.isEmpty())  
  47.             return Collections.unmodifiableSet(keys);  
  48.         else  
  49.             return Collections.emptySet();  
  50.     }  
  51.   
  52.     public Collection<Object> values() {  
  53.         Collection<Object> values = attributes.values();  
  54.         if (!CollectionUtils.isEmpty(values))  
  55.             return Collections.unmodifiableCollection(values);  
  56.         else  
  57.             return Collections.emptySet();  
  58.     }  
  59.   
  60.     public String toString() {  
  61.         return (new StringBuilder("SimpleMapCache '")).append(name).append("' (").append(attributes.size()).append(  
  62.                 " entries)").toString();  
  63.     }  
  64.   
  65. }  


其實上面的cache實現我直接用mapcache實現類的原始碼然後增加實現序列化的介面,比較方便


然後我們把自己的資源搞到一個map裡,然後new SimpleMapCache(Map)就生成一個快取堆,最後新增到快取管理器裡面即可


下面我們看看如何實現快取管理器


所以我們先實現一個自定義的快取管理器介面方便我們操作每一個快取堆


[html] view plain copy
  1. /**  
  2.  *   
  3.  * 快取管理器介面  
  4.  *   
  5.  * @author shadow  
  6.  *   
  7.  */  
  8. public interface SimpleCacheManager {  
  9.   
  10.     /**  
  11.      * 新增快取堆到管理器  
  12.      *   
  13.      * @param name  
  14.      * @param cache  
  15.      */  
  16.     public abstract void createCache(String name, Cache<Object, Object> cache) throws CacheException;  
  17.   
  18.     /**  
  19.      * 獲取快取堆  
  20.      *   
  21.      * @param name  
  22.      * @return  
  23.      * @throws CacheException  
  24.      */  
  25.     public abstract Cache<Object, Object> getCache(String name) throws CacheException;  
  26.   
  27.     /**  
  28.      * 移除快取堆  
  29.      *   
  30.      * @param name  
  31.      * @throws CacheException  
  32.      */  
  33.     public abstract void removeCache(String name) throws CacheException;  
  34.   
  35.     /**  
  36.      * 更新快取堆  
  37.      *   
  38.      * @param name  
  39.      * @param cache  
  40.      */  
  41.     public abstract void updateCahce(String name, Cache<Object, Object> cache) throws CacheException;  
  42.   
  43.     /**  
  44.      * 登出管理器  
  45.      */  
  46.     public abstract void destroy() throws CacheException;  
  47. }  

介面已經定義好,我們就寫一個實現類完成我們的邏輯,並且這個邏輯是把快取堆物件放到memcached裡面


[html] view plain copy
  1. /**  
  2.  *   
  3.  * 快取管理器實現類  
  4.  *   
  5.  * @author shadow  
  6.  *   
  7.  */  
  8. public class SimpleCacheManagerImpl implements SimpleCacheManager {  
  9.   
  10.     private MemcachedClient memcachedClient;  
  11.   
  12.     public SimpleCacheManagerImpl(MemcachedClient memcachedClient) {  
  13.         if (memcachedClient == null) {  
  14.             throw new RuntimeException("必須存在memcached客戶端例項");  
  15.         }  
  16.         this.memcachedClient = memcachedClient;  
  17.     }  
  18.   
  19.     @Override  
  20.     public void createCache(String name, Cache<Object, Object> cache) throws CacheException {  
  21.         try {  
  22.             memcachedClient.set(name, 0, cache);  
  23.         } catch (Exception e) {  
  24.             throw new CacheException(e);  
  25.         }  
  26.     }  
  27.   
  28.     @Override  
  29.     public Cache<Object, Object> getCache(String name) throws CacheException {  
  30.         try {  
  31.             return memcachedClient.get(name);  
  32.         } catch (Exception e) {  
  33.             throw new CacheException(e);  
  34.         }  
  35.     }  
  36.   
  37.     @Override  
  38.     public void removeCache(String name) throws CacheException {  
  39.         try {  
  40.             memcachedClient.delete(name);  
  41.         } catch (Exception e) {  
  42.             throw new CacheException(e);  
  43.         }  
  44.     }  
  45.   
  46.     @Override  
  47.     public void updateCahce(String name, Cache<Object, Object> cache) throws CacheException {  
  48.         try {  
  49.             memcachedClient.replace(name, 0, cache);  
  50.         } catch (Exception e) {  
  51.             throw new CacheException(e);  
  52.         }  
  53.     }  
  54.   
  55.     @Override  
  56.     public void destroy() throws CacheException {  
  57.         try {  
  58.             memcachedClient.shutdown();  
  59.         } catch (Exception e) {  
  60.             throw new CacheException(e);  
  61.         }  
  62.     }  
  63.   
  64. }  


然後我們就開始把這自定義的管理器接入到shiro的快取管理器


[html] view plain copy
  1. /**  
  2.  *   
  3.  * 安全框架快取管理器實現類  
  4.  *   
  5.  * @author shadow  
  6.  *   
  7.  */  
  8. public class ShiroCacheManager implements CacheManager, Destroyable {  
  9.   
  10.     private SimpleCacheManager simpleCacheManager;  
  11.   
  12.     @Override  
  13.     public Cache<Object, Object> getCache(String name) throws CacheException {  
  14.         return simpleCacheManager.getCache(name);  
  15.     }  
  16.   
  17.     @Override  
  18.     public void destroy() throws Exception {  
  19.         simpleCacheManager.destroy();  
  20.     }  
  21.   
  22.     public SimpleCacheManager getSimpleCacheManager() {  
  23.         return simpleCacheManager;  
  24.     }  
  25.   
  26.     public void setSimpleCacheManager(SimpleCacheManager simpleCacheManager) {  
  27.         this.simpleCacheManager = simpleCacheManager;  
  28.     }  
  29.   
  30. }  


最後配置下這個shiro的管理器實現類注入到需要的地方即可


[html] view plain copy
  1. <!-- 安全管理器 -->  
  2.     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
  3.         <property name="sessionManager" ref="sessionManager" />  
  4.         <property name="cacheManager" ref="shiroCacheManager" />  
  5.         <property name="realm" ref="simpleUserRealm" />  
  6.     </bean>  
  7.   
  8.     <!-- 安全框架快取管理器 -->  
  9.     <bean id="shiroCacheManager" class="com.silvery.security.shiro.cache.ShiroCacheManager">  
  10.         <property name="simpleCacheManager" ref="simpleCacheManager" />  
  11.     </bean>  
  12.   
  13.     <!-- 擴充套件快取管理器 -->  
  14.     <bean id="simpleCacheManager"  
  15.         class="com.silvery.security.shiro.cache.extend.impl.SimpleCacheManagerImpl">  
  16.         <constructor-arg ref="memcachedClient" />  
  17.     </bean>  


配置好了之後,我們在需要地方把例項化的SimpeMapCache新增到我們的自己的管理器裡面即可...

相關文章