아파 치 shiro 클 러 스 터 구현 (7) 분포 식 클 러 스 터 시스템 에서 - cache 공유

11796 단어
Apache shiro 클 러 스 터 구현 (1) shiro 입문 안내
Apache shiro 클 러 스 터 구현 (2) shiro 의 INI 설정
아파 치 shiro 클 러 스 터 구현 (3) shiro 인증 (Shiro Authentication)
아파 치 shiro 클 러 스 터 구현 (4) shiro 권한 부여 (Authentication) -- 접근 제어
Apache shiro 클 러 스 터 구현 (5) 분포 식 클 러 스 터 시스템 에서 사용 가능 한 높 은 session 솔 루 션
Apache shiro 클 러 스 터 구현 (6) 분포 식 클 러 스 터 시스템 에서 사용 가능 한 높 은 session 솔 루 션 - Session 공유
아파 치 shiro 클 러 스 터 구현 (7) 분포 식 클 러 스 터 시스템 에서 - cache 공유
Apache shiro 클 러 스 터 구현 (8) 웹 클 러 스 터 시 session 동기 화 3 가지 방법
지난 편 에 서 는 첫 번 째 문제, 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 의 Authorizing Realm 의 방법 이에 요.
<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 군집 의 설정 을 완성 하 였 습 니 다.

좋은 웹페이지 즐겨찾기