上一章我们讲解了如何扩展集中式的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添加到我们的自己的管理器里面即可...
这个章节已经讲完了,谢谢大家的支持
欢迎拍砖...