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. hibernate--HelloWorld

    本次学习版本:hibernate-release-5.2.6.Final,要求java 1.8 和JDBC 4.2. hibernate是一个开放源代码的对象关系映射框架.对JDBC进行了非常轻量的封 ...

  2. 关于sg90舵机的,要知道!要注意!

    这类舵机的转向跟频率和占空比相关,两者缺一不可! 1.在一个特定的频率下,特定的占空比使得舵机会转到一个角度,占空比不变,则角度不会不会变化,所以想要舵机动,就要在国定的频率下不断改变占空比. 2.当 ...

  3. [HNOI 2014]道路堵塞

    Description A国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国 交通部指定了一条从城市1到城市N的路径,并且保证这条路径的长度是所有 ...

  4. [BeiJing2011]元素

    Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔 法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石. 一般地,矿石越多则法力 ...

  5. ●Joyoi Normal

    题链: http://www.joyoi.cn/problem/tyvj-1953题解: 定义d(u,v)这个函数,满足: d(u,v)=1,当且仅当在点分树中,u是v的祖先 d(u,v)=0,其它情 ...

  6. ●洛谷P2664 树上游戏

    题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...

  7. ●BZOJ 3796 Mushroom追妹纸

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3796 题解: 题意:    给出三个串 A,B,C    找出一个最长串 S,    使得 ...

  8. 2015 多校联赛 ——HDU5410(dp)

    Sample Input 1 100 2 10 2 1 20 1 1   Sample Output 21 题意:共有m元钱和n种东西,求每种单价p,而且你买x个该种物品可以得到Ax+B个,求m元钱最 ...

  9. hdu 5112 (2014北京 水)

    题意:有个人在跑步,一直每个时间他所在的位置,求最大速度 #include <iostream> #include <cstring> #include <cstdio& ...

  10. [Codeforces Round #431]简要题解

    来自FallDream的博客,未经允许, 请勿转载,谢谢. 好久没写cf题解了zzz 代码比较丑不贴了,cf上都可以看 Div2A. 给你一个长度为n(n<=100)的序列 判断是否可以分成奇数 ...