Apache shiro集群实现 (七)分布式集群系统下---cache共享
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共享的更多相关文章
- solr 集群(SolrCloud 分布式集群部署步骤)
SolrCloud 分布式集群部署步骤 安装软件包准备 apache-tomcat-7.0.54 jdk1.7 solr-4.8.1 zookeeper-3.4.5 注:以上软件都是基于 Linux ...
- Redis集群模式之分布式集群模式
前言 Redis集群模式主要有2种: 主从集群 分布式集群. 前者主要是为了高可用或是读写分离,后者为了更好的存储数据,负载均衡. 本文主要讲解主从集群.本章主要讲解后一半部分,Redis集群. 与本 ...
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (五)分布式集群系统下的高可用session解决方案
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (八) web集群时session同步的3种方法
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (二) shiro 的INI配置
Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...
- Apache shiro集群实现 (一) shiro入门介绍
近期在ITOO项目中研究使用Apache shiro集群中要解决的两个问题,一个是Session的共享问题,一个是授权信息的cache共享问题,官网上给的例子是Ehcache的实现,在配置说明上不算很 ...
随机推荐
- hibernate--HelloWorld
本次学习版本:hibernate-release-5.2.6.Final,要求java 1.8 和JDBC 4.2. hibernate是一个开放源代码的对象关系映射框架.对JDBC进行了非常轻量的封 ...
- 关于sg90舵机的,要知道!要注意!
这类舵机的转向跟频率和占空比相关,两者缺一不可! 1.在一个特定的频率下,特定的占空比使得舵机会转到一个角度,占空比不变,则角度不会不会变化,所以想要舵机动,就要在国定的频率下不断改变占空比. 2.当 ...
- [HNOI 2014]道路堵塞
Description A国有N座城市,依次标为1到N.同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数.现在,A国 交通部指定了一条从城市1到城市N的路径,并且保证这条路径的长度是所有 ...
- [BeiJing2011]元素
Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔 法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石. 一般地,矿石越多则法力 ...
- ●Joyoi Normal
题链: http://www.joyoi.cn/problem/tyvj-1953题解: 定义d(u,v)这个函数,满足: d(u,v)=1,当且仅当在点分树中,u是v的祖先 d(u,v)=0,其它情 ...
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- ●BZOJ 3796 Mushroom追妹纸
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3796 题解: 题意: 给出三个串 A,B,C 找出一个最长串 S, 使得 ...
- 2015 多校联赛 ——HDU5410(dp)
Sample Input 1 100 2 10 2 1 20 1 1 Sample Output 21 题意:共有m元钱和n种东西,求每种单价p,而且你买x个该种物品可以得到Ax+B个,求m元钱最 ...
- hdu 5112 (2014北京 水)
题意:有个人在跑步,一直每个时间他所在的位置,求最大速度 #include <iostream> #include <cstring> #include <cstdio& ...
- [Codeforces Round #431]简要题解
来自FallDream的博客,未经允许, 请勿转载,谢谢. 好久没写cf题解了zzz 代码比较丑不贴了,cf上都可以看 Div2A. 给你一个长度为n(n<=100)的序列 判断是否可以分成奇数 ...