Apache shiro集群实现 (七)分布式集群系统下---cache共享

上一篇已经解决了第一个问题,session的共享,现在我们解决第二个问题cache的共享。

    

先看下spring的配置文件,上一篇已经提到过了


[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;"><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository">    
  2.     <property name="sessionManager" ref="defaultWebSessionManager" />    
  3.     <property name="realm" ref="shiroDbRealm" />    
  4.     <property name="cacheManager" ref="memoryConstrainedCacheManager" />    
  5. </bean>    
  6. <bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /></span>  


       这里cacheManager我们注入了shiro自定的本机内存实现的cacheManager类,当然,这肯定不满足我们集群的需要,所以我们要自己实现cacheManager类,这里我还是用了redis作为cache的存储,先创建RedisCacheManager实现类


[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">package com.tgb.itoo.authority.cache;  
  2.   
  3. import java.util.concurrent.ConcurrentHashMap;  
  4. import java.util.concurrent.ConcurrentMap;  
  5.   
  6. import org.apache.shiro.cache.Cache;  
  7. import org.apache.shiro.cache.CacheException;  
  8. import org.apache.shiro.cache.CacheManager;  
  9. import org.slf4j.Logger;  
  10. import org.slf4j.LoggerFactory;  
  11.   
  12. public class RedisCacheManager implements CacheManager{  
  13.   
  14.     private static final Logger logger = LoggerFactory  
  15.             .getLogger(RedisCacheManager.class);  
  16.   
  17.     // fast lookup by name map  
  18.     private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();  
  19.   
  20.     private RedisManager redisManager;  
  21.   
  22.     /** 
  23.      * The Redis key prefix for caches  
  24.      */  
  25.     private String keyPrefix = "shiro_redis_cache:";  
  26.       
  27.     /** 
  28.      * Returns the Redis session keys 
  29.      * prefix. 
  30.      * @return The prefix 
  31.      */  
  32.     public String getKeyPrefix() {  
  33.         return keyPrefix;  
  34.     }  
  35.   
  36.     /** 
  37.      * Sets the Redis sessions key  
  38.      * prefix. 
  39.      * @param keyPrefix The prefix 
  40.      */  
  41.     public void setKeyPrefix(String keyPrefix) {  
  42.         this.keyPrefix = keyPrefix;  
  43.     }  
  44.       
  45.     @Override  
  46.     public <K, V> Cache<K, V> getCache(String name) throws CacheException {  
  47.         logger.debug("获取名称为: " + name + " 的RedisCache实例");  
  48.           
  49.         Cache c = caches.get(name);  
  50.           
  51.         if (c == null) {  
  52.   
  53.             // initialize the Redis manager instance  
  54.             redisManager.init();  
  55.               
  56.             // create a new cache instance  
  57.             c = new RedisCache<K, V>(redisManager, keyPrefix);  
  58.               
  59.             // add it to the cache collection  
  60.             caches.put(name, c);  
  61.         }  
  62.         return c;  
  63.     }  
  64.   
  65.     public RedisManager getRedisManager() {  
  66.         return redisManager;  
  67.     }  
  68.   
  69.     public void setRedisManager(RedisManager redisManager) {  
  70.         this.redisManager = redisManager;  
  71.     }  
  72. }  
  73. </span>  

        当然,这里仅仅是getCache,我第一次看源码时,也有这样的疑问,cache的add、remove等等方法在哪里实现呢?我们继续看看shiro的源码就会知道答案了

        这个是自己relm的AuthorizingRealm中的方法


[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">    protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {    
  2.         
  3.             if (principals == null) {    
  4.                 return null;    
  5.             }    
  6.         
  7.             AuthorizationInfo info = null;    
  8.         
  9.             if (log.isTraceEnabled()) {    
  10.                 log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");    
  11.             }    
  12.         
  13.             Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();    
  14.             if (cache != null) {    
  15.                 if (log.isTraceEnabled()) {    
  16.                     log.trace("Attempting to retrieve the AuthorizationInfo from cache.");    
  17.                 }    
  18.                 Object key = getAuthorizationCacheKey(principals);    
  19.                 info = cache.get(key);    
  20.                 if (log.isTraceEnabled()) {    
  21.                     if (info == null) {    
  22.                         log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");    
  23.                     } else {    
  24.                         log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");    
  25.                     }    
  26.                 }    
  27.             }    
  28.             if (info == null) {    
  29.                 // Call template method if the info was not found in a cache     
  30.                 info = <STRONG>doGetAuthorizationInfo</STRONG>(principals);    
  31.                 // If the info is not null and the cache has been created, then cache the authorization info.     
  32.                 if (info != null && cache != null) {    
  33.                     if (log.isTraceEnabled()) {    
  34.                         log.trace("Caching authorization info for principals: [" + principals + "].");    
  35.                     }    
  36.                     Object key = getAuthorizationCacheKey(principals);    
  37.                     <STRONG>cache.put</STRONG>(key, info);    
  38.                 }    
  39.             }    
  40.             return info;    
  41.         }  </span>  


       如果大家去查查引入就知道我们自定义relm要实现一个叫做doGetAuthorizationInfo()的方法,它的作用是查询授权信息,我们注意加粗的2行,发现其实cache的put方法其实才是cache存储的核心类,其实现都在cache中,所以我们需要实现自己的cache,创建RedisCache类


[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">package com.tgb.itoo.authority.cache;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collection;  
  5. import java.util.Collections;  
  6. import java.util.HashSet;  
  7. import java.util.List;  
  8. import java.util.Set;  
  9.   
  10.   
  11. import org.apache.shiro.cache.Cache;  
  12. import org.apache.shiro.cache.CacheException;  
  13. import org.apache.shiro.util.CollectionUtils;  
  14. import org.slf4j.Logger;  
  15. import org.slf4j.LoggerFactory;  
  16.   
  17. public class RedisCache<K,V> implements Cache<K,V> {  
  18.   
  19.     private Logger logger = LoggerFactory.getLogger(this.getClass());  
  20.       
  21.     /** 
  22.      * The wrapped Jedis instance. 
  23.      */  
  24.     private RedisManager cache;  
  25.       
  26.     /** 
  27.      * The Redis key prefix for the sessions  
  28.      */  
  29.     private String keyPrefix = "shiro_redis_session:";  
  30.       
  31.     /** 
  32.      * Returns the Redis session keys 
  33.      * prefix. 
  34.      * @return The prefix 
  35.      */  
  36.     public String getKeyPrefix() {  
  37.         return keyPrefix;  
  38.     }  
  39.   
  40.     /** 
  41.      * Sets the Redis sessions key  
  42.      * prefix. 
  43.      * @param keyPrefix The prefix 
  44.      */  
  45.     public void setKeyPrefix(String keyPrefix) {  
  46.         this.keyPrefix = keyPrefix;  
  47.     }  
  48.       
  49.     /** 
  50.      * 通过一个JedisManager实例构造RedisCache 
  51.      */  
  52.     public RedisCache(RedisManager cache){  
  53.          if (cache == null) {  
  54.              throw new IllegalArgumentException("Cache argument cannot be null.");  
  55.          }  
  56.          this.cache = cache;  
  57.     }  
  58.       
  59.     /** 
  60.      * Constructs a cache instance with the specified 
  61.      * Redis manager and using a custom key prefix. 
  62.      * @param cache The cache manager instance 
  63.      * @param prefix The Redis key prefix 
  64.      */  
  65.     public RedisCache(RedisManager cache,   
  66.                 String prefix){  
  67.            
  68.         this( cache );  
  69.           
  70.         // set the prefix  
  71.         this.keyPrefix = prefix;  
  72.     }  
  73.       
  74.     /** 
  75.      * 获得byte[]型的key 
  76.      * @param key 
  77.      * @return 
  78.      */  
  79.     private byte[] getByteKey(K key){  
  80.         if(key instanceof String){  
  81.             String preKey = this.keyPrefix + key;  
  82.             return preKey.getBytes();  
  83.         }else{  
  84.             return SerializeUtils.serialize(key);  
  85.         }  
  86.     }  
  87.       
  88.     @Override  
  89.     public V get(K key) throws CacheException {  
  90.         logger.debug("根据key从Redis中获取对象 key [" + key + "]");  
  91.         try {  
  92.             if (key == null) {  
  93.                 return null;  
  94.             }else{  
  95.                 byte[] rawValue = cache.get(getByteKey(key));  
  96.                 @SuppressWarnings("unchecked")  
  97.                 V value = (V)SerializeUtils.deserialize(rawValue);  
  98.                 return value;  
  99.             }  
  100.         } catch (Throwable t) {  
  101.             throw new CacheException(t);  
  102.         }  
  103.   
  104.     }  
  105.   
  106.     @Override  
  107.     public V put(K key, V value) throws CacheException {  
  108.         logger.debug("根据key从存储 key [" + key + "]");  
  109.          try {  
  110.                 cache.set(getByteKey(key), SerializeUtils.serialize(value));  
  111.                 return value;  
  112.             } catch (Throwable t) {  
  113.                 throw new CacheException(t);  
  114.             }  
  115.     }  
  116.   
  117.     @Override  
  118.     public V remove(K key) throws CacheException {  
  119.         logger.debug("从redis中删除 key [" + key + "]");  
  120.         try {  
  121.             V previous = get(key);  
  122.             cache.del(getByteKey(key));  
  123.             return previous;  
  124.         } catch (Throwable t) {  
  125.             throw new CacheException(t);  
  126.         }  
  127.     }  
  128.   
  129.     @Override  
  130.     public void clear() throws CacheException {  
  131.         logger.debug("从redis中删除所有元素");  
  132.         try {  
  133.             cache.flushDB();  
  134.         } catch (Throwable t) {  
  135.             throw new CacheException(t);  
  136.         }  
  137.     }  
  138.   
  139.     @Override  
  140.     public int size() {  
  141.         try {  
  142.             Long longSize = new Long(cache.dbSize());  
  143.             return longSize.intValue();  
  144.         } catch (Throwable t) {  
  145.             throw new CacheException(t);  
  146.         }  
  147.     }  
  148.   
  149.     @SuppressWarnings("unchecked")  
  150.     @Override  
  151.     public Set<K> keys() {  
  152.         try {  
  153.             Set<byte[]> keys = cache.keys(this.keyPrefix + "*");  
  154.             if (CollectionUtils.isEmpty(keys)) {  
  155.                 return Collections.emptySet();  
  156.             }else{  
  157.                 Set<K> newKeys = new HashSet<K>();  
  158.                 for(byte[] key:keys){  
  159.                     newKeys.add((K)key);  
  160.                 }  
  161.                 return newKeys;  
  162.             }  
  163.         } catch (Throwable t) {  
  164.             throw new CacheException(t);  
  165.         }  
  166.     }  
  167.   
  168.     @Override  
  169.     public Collection<V> values() {  
  170.         try {  
  171.             Set<byte[]> keys = cache.keys(this.keyPrefix + "*");  
  172.             if (!CollectionUtils.isEmpty(keys)) {  
  173.                 List<V> values = new ArrayList<V>(keys.size());  
  174.                 for (byte[] key : keys) {  
  175.                     @SuppressWarnings("unchecked")  
  176.                     V value = get((K)key);  
  177.                     if (value != null) {  
  178.                         values.add(value);  
  179.                     }  
  180.                 }  
  181.                 return Collections.unmodifiableList(values);  
  182.             } else {  
  183.                 return Collections.emptyList();  
  184.             }  
  185.         } catch (Throwable t) {  
  186.             throw new CacheException(t);  
  187.         }  
  188.     }  
  189. }  
  190. </span>  


最后修改spring配置文件


[html]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;"><!-- 第三:shiro管理中心类 start-李社河 -->  
  2.     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
  3.         <property name="realm" ref="shiroRealm"></property>  
  4.         <property name="sessionMode" value="http"></property>  
  5.         <property name="subjectFactory" ref="casSubjectFactory"></property>  
  6.         <!-- ehcahe缓存shiro自带 -->  
  7.         <!-- <property name="cacheManager" ref="shiroEhcacheManager"></property> -->  
  8.   
  9.         <!-- redis缓存 -->  
  10.         <property name="cacheManager" ref="redisCacheManager" />  
  11.   
  12.         <!-- sessionManager -->  
  13.         <property name="sessionManager" ref="sessionManager"></property>  
  14.     </bean></span>  

这样就完成了整个shiro集群的配置



转自:http://blog.csdn.net/lishehe/article/details/45224181

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值