apache shiro集群实现(二)— cache共享
2013-05-05 12:33
323 查看
上一篇已经解决了第一个问题,session的共享,现在我们解决第二个问题cache的共享。
先看下spring的配置文件,上一篇已经提到过了
[html]
view plaincopyprint?
<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" />
这里cacheManager我们注入了shiro自定的本机内存实现的cacheManager类,当然,这肯定不满足我们集群的需要,所以我们要自己实现cacheManager类,这里我还是用了redis作为cache的存储,先创建CustomShiroCacheManager实现类
[java]
view plaincopyprint?
public class CustomShiroCacheManager implements CacheManager, Destroyable { private ShiroCacheManager shiroCacheManager; public ShiroCacheManager getShiroCacheManager() { return shiroCacheManager; } public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) { this.shiroCacheManager = shiroCacheManager; } @Override public <K, V> Cache<K, V> getCache(String name) throws CacheException { return getShiroCacheManager().getCache(name); } @Override public void destroy() throws Exception { shiroCacheManager.destroy(); } }
这里为了扩展,引入了ShiroCacheManager接口
[java]
view plaincopyprint?
public interface ShiroCacheManager { <K, V> Cache<K, V> getCache(String name); void destroy(); }
[java]
view plaincopyprint?
public class JedisShiroCacheManager implements ShiroCacheManager { @Autowired private JedisCacheManager jedisCacheManager; @Override public <K, V> Cache<K, V> getCache(String name) { return new JedisShiroCache<K, V>(name, jedisCacheManager); } @Override public void destroy() { jedisCacheManager.getJedis().shutdown(); } }
当然,这里仅仅是getCache,我第一次看源码时,也有这样的疑问,cache的add、remove等等方法在哪里实现呢?我们继续看看shiro的源码就会知道答案了
这个是自己relm的AuthorizingRealm中的方法
[java]
view plaincopyprint?
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;
}
如果大家去查查引入就知道我们自定义relm要实现一个叫做doGetAuthorizationInfo()的方法,它的作用是查询授权信息,我们注意加粗的2行,发现其实cache的put方法其实才是cache存储的核心类,其实现都在cache中,所以我们需要实现自己的cache,创建JedisShiroCache类
[java]
view plaincopyprint?
public class JedisShiroCache<K, V> implements Cache<K, V> {
private final String REDIS_SHIRO_CACHE = "shiro-cache:";
private JedisManager jedisManager;
private String name;
public JedisShiroCache(String name, JedisManager jedisManager) {
this.name = name;
this.jedisManager = jedisManager;
}
/**
* 自定义relm中的授权/认证的类名加上授权/认证英文名字
* @return
*/
public String getName() {
if (name == null)
return "";
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public V get(K key) throws CacheException {
byte[] byteKey = SerializeUtil.serialize(getCacheKey(key));
byte[] byteValue = jedisManager.getValueByKey(byteKey);
return (V) SerializeUtil.deserialize(byteValue);
}
@Override
public V put(K key, V value) throws CacheException {
V previos = get(key);
jedisManager.saveValueByKey(SerializeUtil.serialize(getCacheKey(key)),
SerializeUtil.serialize(value));
return previos;
}
@Override
public V remove(K key) throws CacheException {
V previos = get(key);
jedisManager.deleteByKey(SerializeUtil.serialize(getCacheKey(key)));
return previos;
}
@Override
public void clear() throws CacheException {
byte[] keysPattern = SerializeUtil.serialize(this.REDIS_SHIRO_CACHE
+ "*");
jedisManager.deleteByKeysPattern(keysPattern);
}
@Override
public int size() {
if (keys() == null)
return 0;
return keys().size();
}
@Override
public Set<K> keys() {
Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil
.serialize(this.REDIS_SHIRO_CACHE + "*"));
Set<K> keys = new HashSet<K>();
for (byte[] bs : byteSet) {
keys.add((K) SerializeUtil.deserialize(bs));
}
return keys;
}
@Override
public Collection<V> values() {
Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil
.serialize(this.REDIS_SHIRO_CACHE + "*"));
List<V> result = new LinkedList<V>();
for (byte[] bs : byteSet) {
result.add((V) SerializeUtil.deserialize(jedisManager
.getValueByKey(bs)));
}
return result;
}
private String getCacheKey(Object key) {
return this.REDIS_SHIRO_CACHE + getName() + ":" + key;
}
最后修改spring配置文件
[html]
view plaincopyprint?
<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="customShiroCacheManager" /> </bean> <bean id="customShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.CustomShiroCacheManager"> <property name="shiroCacheManager" ref="jedisShiroCacheManager" /> </bean> <bean id="jedisShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.JedisShiroCacheManager" />
这样就完成了整个shiro集群的配置
先看下spring的配置文件,上一篇已经提到过了
[html]
view plaincopyprint?
<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" />
<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" />
这里cacheManager我们注入了shiro自定的本机内存实现的cacheManager类,当然,这肯定不满足我们集群的需要,所以我们要自己实现cacheManager类,这里我还是用了redis作为cache的存储,先创建CustomShiroCacheManager实现类
[java]
view plaincopyprint?
public class CustomShiroCacheManager implements CacheManager, Destroyable { private ShiroCacheManager shiroCacheManager; public ShiroCacheManager getShiroCacheManager() { return shiroCacheManager; } public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) { this.shiroCacheManager = shiroCacheManager; } @Override public <K, V> Cache<K, V> getCache(String name) throws CacheException { return getShiroCacheManager().getCache(name); } @Override public void destroy() throws Exception { shiroCacheManager.destroy(); } }
public class CustomShiroCacheManager implements CacheManager, Destroyable { private ShiroCacheManager shiroCacheManager; public ShiroCacheManager getShiroCacheManager() { return shiroCacheManager; } public void setShiroCacheManager(ShiroCacheManager shiroCacheManager) { this.shiroCacheManager = shiroCacheManager; } @Override public <K, V> Cache<K, V> getCache(String name) throws CacheException { return getShiroCacheManager().getCache(name); } @Override public void destroy() throws Exception { shiroCacheManager.destroy(); } }
这里为了扩展,引入了ShiroCacheManager接口
[java]
view plaincopyprint?
public interface ShiroCacheManager { <K, V> Cache<K, V> getCache(String name); void destroy(); }
public interface ShiroCacheManager { <K, V> Cache<K, V> getCache(String name); void destroy(); }下面我们自己实现redis的cacheManger
[java]
view plaincopyprint?
public class JedisShiroCacheManager implements ShiroCacheManager { @Autowired private JedisCacheManager jedisCacheManager; @Override public <K, V> Cache<K, V> getCache(String name) { return new JedisShiroCache<K, V>(name, jedisCacheManager); } @Override public void destroy() { jedisCacheManager.getJedis().shutdown(); } }
public class JedisShiroCacheManager implements ShiroCacheManager { @Autowired private JedisCacheManager jedisCacheManager; @Override public <K, V> Cache<K, V> getCache(String name) { return new JedisShiroCache<K, V>(name, jedisCacheManager); } @Override public void destroy() { jedisCacheManager.getJedis().shutdown(); } }
当然,这里仅仅是getCache,我第一次看源码时,也有这样的疑问,cache的add、remove等等方法在哪里实现呢?我们继续看看shiro的源码就会知道答案了
这个是自己relm的AuthorizingRealm中的方法
[java]
view plaincopyprint?
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;
}
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 = doGetAuthorizationInfo(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); cache.put(key, info); } } return info; }
如果大家去查查引入就知道我们自定义relm要实现一个叫做doGetAuthorizationInfo()的方法,它的作用是查询授权信息,我们注意加粗的2行,发现其实cache的put方法其实才是cache存储的核心类,其实现都在cache中,所以我们需要实现自己的cache,创建JedisShiroCache类
[java]
view plaincopyprint?
public class JedisShiroCache<K, V> implements Cache<K, V> {
private final String REDIS_SHIRO_CACHE = "shiro-cache:";
private JedisManager jedisManager;
private String name;
public JedisShiroCache(String name, JedisManager jedisManager) {
this.name = name;
this.jedisManager = jedisManager;
}
/**
* 自定义relm中的授权/认证的类名加上授权/认证英文名字
* @return
*/
public String getName() {
if (name == null)
return "";
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public V get(K key) throws CacheException {
byte[] byteKey = SerializeUtil.serialize(getCacheKey(key));
byte[] byteValue = jedisManager.getValueByKey(byteKey);
return (V) SerializeUtil.deserialize(byteValue);
}
@Override
public V put(K key, V value) throws CacheException {
V previos = get(key);
jedisManager.saveValueByKey(SerializeUtil.serialize(getCacheKey(key)),
SerializeUtil.serialize(value));
return previos;
}
@Override
public V remove(K key) throws CacheException {
V previos = get(key);
jedisManager.deleteByKey(SerializeUtil.serialize(getCacheKey(key)));
return previos;
}
@Override
public void clear() throws CacheException {
byte[] keysPattern = SerializeUtil.serialize(this.REDIS_SHIRO_CACHE
+ "*");
jedisManager.deleteByKeysPattern(keysPattern);
}
@Override
public int size() {
if (keys() == null)
return 0;
return keys().size();
}
@Override
public Set<K> keys() {
Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil
.serialize(this.REDIS_SHIRO_CACHE + "*"));
Set<K> keys = new HashSet<K>();
for (byte[] bs : byteSet) {
keys.add((K) SerializeUtil.deserialize(bs));
}
return keys;
}
@Override
public Collection<V> values() {
Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil
.serialize(this.REDIS_SHIRO_CACHE + "*"));
List<V> result = new LinkedList<V>();
for (byte[] bs : byteSet) {
result.add((V) SerializeUtil.deserialize(jedisManager
.getValueByKey(bs)));
}
return result;
}
private String getCacheKey(Object key) {
return this.REDIS_SHIRO_CACHE + getName() + ":" + key;
}
public class JedisShiroCache<K, V> implements Cache<K, V> { private final String REDIS_SHIRO_CACHE = "shiro-cache:"; private JedisManager jedisManager; private String name; public JedisShiroCache(String name, JedisManager jedisManager) { this.name = name; this.jedisManager = jedisManager; } /** * 自定义relm中的授权/认证的类名加上授权/认证英文名字 * @return */ public String getName() { if (name == null) return ""; return name; } public void setName(String name) { this.name = name; } @Override public V get(K key) throws CacheException { byte[] byteKey = SerializeUtil.serialize(getCacheKey(key)); byte[] byteValue = jedisManager.getValueByKey(byteKey); return (V) SerializeUtil.deserialize(byteValue); } @Override public V put(K key, V value) throws CacheException { V previos = get(key); jedisManager.saveValueByKey(SerializeUtil.serialize(getCacheKey(key)), SerializeUtil.serialize(value)); return previos; } @Override public V remove(K key) throws CacheException { V previos = get(key); jedisManager.deleteByKey(SerializeUtil.serialize(getCacheKey(key))); return previos; } @Override public void clear() throws CacheException { byte[] keysPattern = SerializeUtil.serialize(this.REDIS_SHIRO_CACHE + "*"); jedisManager.deleteByKeysPattern(keysPattern); } @Override public int size() { if (keys() == null) return 0; return keys().size(); } @Override public Set<K> keys() { Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil .serialize(this.REDIS_SHIRO_CACHE + "*")); Set<K> keys = new HashSet<K>(); for (byte[] bs : byteSet) { keys.add((K) SerializeUtil.deserialize(bs)); } return keys; } @Override public Collection<V> values() { Set<byte[]> byteSet = jedisManager.getKeysByKeysPattern(SerializeUtil .serialize(this.REDIS_SHIRO_CACHE + "*")); List<V> result = new LinkedList<V>(); for (byte[] bs : byteSet) { result.add((V) SerializeUtil.deserialize(jedisManager .getValueByKey(bs))); } return result; } private String getCacheKey(Object key) { return this.REDIS_SHIRO_CACHE + getName() + ":" + key; }
最后修改spring配置文件
[html]
view plaincopyprint?
<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="customShiroCacheManager" /> </bean> <bean id="customShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.CustomShiroCacheManager"> <property name="shiroCacheManager" ref="jedisShiroCacheManager" /> </bean> <bean id="jedisShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.JedisShiroCacheManager" />
<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="customShiroCacheManager" /> </bean> <bean id="customShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.CustomShiroCacheManager"> <property name="shiroCacheManager" ref="jedisShiroCacheManager" /> </bean> <bean id="jedisShiroCacheManager" class="com.nfschina.fourjoy.security.shiro.custom.cache.JedisShiroCacheManager" />
这样就完成了整个shiro集群的配置
相关文章推荐
- apache shiro集群实现(二)— cache共享
- apache shiro集群实现(二)— cache共享
- apache shiro集群实现(一) session共享
- apache shiro集群实现(一) session共享
- apache shiro集群实现(一) session共享
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- Apache shiro集群实现 (六)分布式集群系统下的高可用session解决方案---Session共享
- Apache shiro集群实现 (一) shiro入门介绍
- Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)
- Apache+tomcat实现负载均衡集群和session共享、tengine+tomcat实现web动静分离
- Apache shiro集群实现 (八) web集群时session同步的3种方法
- Apache shiro集群实现 (一) shiro入门介绍
- Apache shiro集群实现 (一) shiro入门介绍
- Apache shiro集群实现 (八) web集群时session同步的3种方法
- Apache + Tomcat + mod_jk实现集群服务及session共享
- Apache shiro集群实现 (三)shiro身份认证(Shiro Authentication)
- Apache shiro集群实现 (四)shiro授权(Authentication)--访问控制
- Shiro+Redis实现tomcat集群session共享