Apache shiro集群实现 (一) shiro入门介绍

Apache shiro集群实现 (二) shiro 的INI配置

Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)

Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制

Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案

Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享

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

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

<span style="font-size:18px;"><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository,roleRepository">
<property name="sessionManager" ref="defaultWebSessionManager" />
<property name="realm" ref="shiroDbRealm" />
<property name="cacheManager" ref="memoryConstrainedCacheManager" />
</bean>
<bean id="memoryConstrainedCacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /></span>

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

<span style="font-size:18px;">package com.tgb.itoo.authority.cache;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class RedisCacheManager implements CacheManager{ private static final Logger logger = LoggerFactory
.getLogger(RedisCacheManager.class); // fast lookup by name map
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>(); private RedisManager redisManager; /**
* The Redis key prefix for caches
*/
private String keyPrefix = "shiro_redis_cache:"; /**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
} /**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
} @Override
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
logger.debug("获取名称为: " + name + " 的RedisCache实例"); Cache c = caches.get(name); if (c == null) { // initialize the Redis manager instance
redisManager.init(); // create a new cache instance
c = new RedisCache<K, V>(redisManager, keyPrefix); // add it to the cache collection
caches.put(name, c);
}
return c;
} public RedisManager getRedisManager() {
return redisManager;
} public void setRedisManager(RedisManager redisManager) {
this.redisManager = redisManager;
}
}
</span>

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

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

<span style="font-size:18px;">    protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {  

            if (principals == null) {
return null;
} AuthorizationInfo info = null; if (log.isTraceEnabled()) {
log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]");
} Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache();
if (cache != null) {
if (log.isTraceEnabled()) {
log.trace("Attempting to retrieve the AuthorizationInfo from cache.");
}
Object key = getAuthorizationCacheKey(principals);
info = cache.get(key);
if (log.isTraceEnabled()) {
if (info == null) {
log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]");
} else {
log.trace("AuthorizationInfo found in cache for principals [" + principals + "]");
}
}
}
if (info == null) {
// Call template method if the info was not found in a cache
info = <STRONG>doGetAuthorizationInfo</STRONG>(principals);
// If the info is not null and the cache has been created, then cache the authorization info.
if (info != null && cache != null) {
if (log.isTraceEnabled()) {
log.trace("Caching authorization info for principals: [" + principals + "].");
}
Object key = getAuthorizationCacheKey(principals);
<STRONG>cache.put</STRONG>(key, info);
}
}
return info;
} </span>

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

<span style="font-size:18px;">package com.tgb.itoo.authority.cache;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class RedisCache<K,V> implements Cache<K,V> { private Logger logger = LoggerFactory.getLogger(this.getClass()); /**
* The wrapped Jedis instance.
*/
private RedisManager cache; /**
* The Redis key prefix for the sessions
*/
private String keyPrefix = "shiro_redis_session:"; /**
* Returns the Redis session keys
* prefix.
* @return The prefix
*/
public String getKeyPrefix() {
return keyPrefix;
} /**
* Sets the Redis sessions key
* prefix.
* @param keyPrefix The prefix
*/
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
} /**
* 通过一个JedisManager实例构造RedisCache
*/
public RedisCache(RedisManager cache){
if (cache == null) {
throw new IllegalArgumentException("Cache argument cannot be null.");
}
this.cache = cache;
} /**
* Constructs a cache instance with the specified
* Redis manager and using a custom key prefix.
* @param cache The cache manager instance
* @param prefix The Redis key prefix
*/
public RedisCache(RedisManager cache,
String prefix){ this( cache ); // set the prefix
this.keyPrefix = prefix;
} /**
* 获得byte[]型的key
* @param key
* @return
*/
private byte[] getByteKey(K key){
if(key instanceof String){
String preKey = this.keyPrefix + key;
return preKey.getBytes();
}else{
return SerializeUtils.serialize(key);
}
} @Override
public V get(K key) throws CacheException {
logger.debug("根据key从Redis中获取对象 key [" + key + "]");
try {
if (key == null) {
return null;
}else{
byte[] rawValue = cache.get(getByteKey(key));
@SuppressWarnings("unchecked")
V value = (V)SerializeUtils.deserialize(rawValue);
return value;
}
} catch (Throwable t) {
throw new CacheException(t);
} } @Override
public V put(K key, V value) throws CacheException {
logger.debug("根据key从存储 key [" + key + "]");
try {
cache.set(getByteKey(key), SerializeUtils.serialize(value));
return value;
} catch (Throwable t) {
throw new CacheException(t);
}
} @Override
public V remove(K key) throws CacheException {
logger.debug("从redis中删除 key [" + key + "]");
try {
V previous = get(key);
cache.del(getByteKey(key));
return previous;
} catch (Throwable t) {
throw new CacheException(t);
}
} @Override
public void clear() throws CacheException {
logger.debug("从redis中删除所有元素");
try {
cache.flushDB();
} catch (Throwable t) {
throw new CacheException(t);
}
} @Override
public int size() {
try {
Long longSize = new Long(cache.dbSize());
return longSize.intValue();
} catch (Throwable t) {
throw new CacheException(t);
}
} @SuppressWarnings("unchecked")
@Override
public Set<K> keys() {
try {
Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}else{
Set<K> newKeys = new HashSet<K>();
for(byte[] key:keys){
newKeys.add((K)key);
}
return newKeys;
}
} catch (Throwable t) {
throw new CacheException(t);
}
} @Override
public Collection<V> values() {
try {
Set<byte[]> keys = cache.keys(this.keyPrefix + "*");
if (!CollectionUtils.isEmpty(keys)) {
List<V> values = new ArrayList<V>(keys.size());
for (byte[] key : keys) {
@SuppressWarnings("unchecked")
V value = get((K)key);
if (value != null) {
values.add(value);
}
}
return Collections.unmodifiableList(values);
} else {
return Collections.emptyList();
}
} catch (Throwable t) {
throw new CacheException(t);
}
}
}
</span>

最后修改spring配置文件

<span style="font-size:18px;"><!-- 第三:shiro管理中心类 start-李社河 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroRealm"></property>
<property name="sessionMode" value="http"></property>
<property name="subjectFactory" ref="casSubjectFactory"></property>
<!-- ehcahe缓存shiro自带 -->
<!-- <property name="cacheManager" ref="shiroEhcacheManager"></property> --> <!-- redis缓存 -->
<property name="cacheManager" ref="redisCacheManager" /> <!-- sessionManager -->
<property name="sessionManager" ref="sessionManager"></property>
</bean></span>

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

Apache shiro集群实现 (七)分布式集群系统下---cache共享的更多相关文章

  1. solr 集群(SolrCloud 分布式集群部署步骤)

    SolrCloud 分布式集群部署步骤 安装软件包准备 apache-tomcat-7.0.54 jdk1.7 solr-4.8.1 zookeeper-3.4.5 注:以上软件都是基于 Linux ...

  2. Redis集群模式之分布式集群模式

    前言 Redis集群模式主要有2种: 主从集群 分布式集群. 前者主要是为了高可用或是读写分离,后者为了更好的存储数据,负载均衡. 本文主要讲解主从集群.本章主要讲解后一半部分,Redis集群. 与本 ...

  3. Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  4. Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  5. Apache shiro集群实现 (八) web集群时session同步的3种方法

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  6. Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  7. Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  8. Apache shiro集群实现 (二) shiro 的INI配置

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  9. Apache shiro集群实现 (一) shiro入门介绍

    近期在ITOO项目中研究使用Apache shiro集群中要解决的两个问题,一个是Session的共享问题,一个是授权信息的cache共享问题,官网上给的例子是Ehcache的实现,在配置说明上不算很 ...

随机推荐

  1. [LeetCode] Parse Lisp Expression 解析Lisp表达式

    You are given a string expression representing a Lisp-like expression to return the integer value of ...

  2. 一个web程序员的年终总结

    2017年年终总结(就是一个程序员的瞎叨叨): 从来到中科院到现在,很开心可以在这留下来.毕竟对于我来说,这里符合我对自己毕业后前两年的规划.我是一个很慢的人,特别是对于我想做好的事情,我会非常认真仔 ...

  3. IDEA2017.3.4破解方式

    下载jetbrainsCrack-2.7-release-str.jar包 下载地址: https://files.cnblogs.com/files/xifenglou/JetBrains.zip ...

  4. [HAOI2011]向量

    题目描述 给你一对数a,b,你可以任意使用(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), (-b,a), (-b,-a)这些向量,问你能不能拼出另一个向量 ...

  5. [HNOI2004]敲砖块

    题目描述 在一个凹槽中放置了 n 层砖块.最上面的一层有n 块砖,从上到下每层依次减少一块砖.每块砖 都有一个分值,敲掉这块砖就能得到相应的分值,如下图所示. 14 15 4 3 23 33 33 7 ...

  6. 2015 多校联赛 ——HDU5289(二分+ST)

    Assignment Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total ...

  7. bzoj1069 [SCOI2007]最大土地面积 旋转卡壳

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3767  Solved: 1501[Submit][Sta ...

  8. BZOJ4079 [Wf2014]Pachinko

    完整题面: 设f(i,j)表示路径经过(i,j)这个点的概率,列出方程消元. 但暴力消元的复杂度是$O((nm)^3)$,注意每一次消元只会影响前后m个方程,所以我们可以对于第i行,只存[i-m,i+ ...

  9. MQ(消息队列)常见的应用场景解析

    前言 提高系统性能首先考虑的是数据库的优化,之前一篇文章<数据库的使用你可能忽略了这些>中有提到过开发中,针对数据库需要注意的事项.但是数据库因为历史原因,横向扩展是一件非常复杂的工程,所 ...

  10. 给小白看的KMP算法

    浅谈KMP算法: (大部分人的KMP写法都是不一样的) 一: 先给大家推荐一个讲kmp特别好理解的一个博客:阮一峰 二: 再给大家介绍一点相关概念: 栗子:  P串: ABCBD 前缀:A,AB,AB ...