利用Redis共享Tomcat中的Session

想要作Tomcat集羣,其中須要解決的一個問題就是多個Tomcat中session的共享。共享的方法有不少種,好比使用Tomcat自帶的session複製,使用數據庫等。這裏一些介紹我使用過的方法。java

1.替換Tomcat的sessionManager

這種方法實現起來比較容易,可是須要改動每一個Tomcat服務器的配置。對於Tomcat6和7,能夠使用tomcat-redis-session-manager庫來實現,對於Tomcat8以及8以上的版本,能夠搜索對應的庫。git

tomcat-redis-session-manager(Github):https://github.com/jcoleman/tomcat-redis-session-managergithub

庫的介紹裏有詳細的使用方法,這裏再簡單列一下:web

  1. 修改  TOMCAT_BASE/conf  目錄下的  context.xml  文件,示例配置以下:
    <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
    <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
             host="localhost" <!-- 非必填: 默認值 "localhost" -->
             port="6379" <!-- 非必填: 默認值 "6379" -->
             database="0" <!-- 非必填: 默認值 "0" -->
             maxInactiveInterval="60" <!-- 非必填: 默認值 "60" (秒) -->
             sessionPersistPolicies="PERSIST_POLICY_1,PERSIST_POLICY_2,.." <!-- 非必填 -->
             sentinelMaster="SentinelMasterName" <!-- 非必填 -->
             sentinels="sentinel-host-1:port,sentinel-host-2:port,.." <!-- 非必填 --> />

    注意:Value標籤必須在Manager標籤以前redis

  2. 將如下依賴包拷貝到  TOMCAT_BASE/lib  目錄
  • tomcat-redis-session-manager-VERSION.jar
  • jedis-2.5.2.jar
  • commons-pool2-2.2.jar

重啓Tomcat後生效。數據庫

 

若是項目中使用了Spring和Apache Shiro,能夠使用下面的方法。apache

2.繼承Shiro的AbstractSessionDAO

序列化工具示例:tomcat

import java.io.Serializable;

import org.apache.commons.lang3.SerializationUtils;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.session.Session;

public class ShiroSerializationUtils {

	public static String serialize(Session session) {
    	return  Base64.encodeToString(SerializationUtils.serialize((Serializable) session));
    }
    
    public static Session deserialize(String sessionStr) {
    	return SerializationUtils.deserialize(Base64.decode(sessionStr));
    }

}

 

Redis操做類示例:服務器

import java.util.Set;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisManager {
	
	private String url = null;
	
	private int port = 6379;
	
	private int timeout = 0;
	
	private String password = null;
	
	private JedisPool jedisPool   = null;

    public RedisManager(){
    }

    @PostConstruct
	public void init() {
    	url = StringUtils.defaultIfBlank(url, "127.0.0.1");
		if(StringUtils.isNotBlank(password)) {
			jedisPool = new JedisPool(new JedisPoolConfig(), url, port, timeout, password);
		} else if (timeout != 0) {
			jedisPool = new JedisPool(new JedisPoolConfig(), url, port, timeout);
		} else {
			jedisPool = new JedisPool(new JedisPoolConfig(), url, port);
		}
	}
	
	public Jedis getJedis() {
        return jedisPool.getResource();
    }
	
	public String get(String key){
        try(Jedis jedis = jedisPool.getResource();){
        	return jedis.get(key);
        }
    }
	
	public void set(String key, String value){
        try(Jedis jedis = jedisPool.getResource();){
        	jedis.set(key, value);
        }
    }
	
	public void set(String key, String value, int timeToLiveSeconds){
        try(Jedis jedis = jedisPool.getResource();){
        	jedis.setex(key, timeToLiveSeconds, value);
        }
    }
	
	public void del(String key){
        try(Jedis jedis = jedisPool.getResource();){
        	jedis.del(key);
        }
    }
	
	public Set<String> keys(String pattern){
        try(Jedis jedis = jedisPool.getResource();){
        	return jedis.keys(pattern);
        }
    }

	public void setUrl(String url) {
		this.url = url;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}

 

實現AbstractSessionDAO示例:session

import java.io.Serializable;
import java.util.Collection;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class RedisSessionDao extends AbstractSessionDAO {
	
	private static final Logger log = LoggerFactory.getLogger(RedisSessionDao.class);
	
	private int expirationTime = 1800; // 超時時間,秒
	
	private RedisManager redisManager;

	@Override
	protected Serializable doCreate(Session session) {
		log.debug("Create session: '{}'",session.getId());
		Serializable sessionId = this.generateSessionId(session);
		assignSessionId(session, sessionId);

		String value = ShiroSerializationUtils.serialize(session);
		redisManager.set(String.valueOf(sessionId), value, expirationTime);
		return sessionId;
	}
	
	@Override
	public void update(Session session) throws UnknownSessionException {
		log.debug("update session: '{}'",session.getId());
		
		if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
            return;
        }
		
		redisManager.set(String.valueOf(session.getId()),ShiroSerializationUtils.serialize(session), expirationTime);
	}

	@Override
	public void delete(Session session) {
		log.debug("delete session: '{}'",session.getId());
		redisManager.del(String.valueOf(session.getId()));
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		log.debug("Read session: '{}'",sessionId);
		
		String sessionStr = redisManager.get(String.valueOf(sessionId));
		return sessionStr == null ? null : ShiroSerializationUtils.deserialize(sessionStr);
	}
	
	//使用 會話驗證調度器 需實現此方法
	@Override
	public Collection<Session> getActiveSessions() {
		return null;
	}

	public void setExpirationTime(int expirationTime) {
		this.expirationTime = expirationTime;
	}

	public void setRedisManager(RedisManager redisManager) {
		this.redisManager = redisManager;
	}
	
}

 

Spring對應部分配置示例:

<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="sessionDAO" ref="redisSessionDao"/>
</bean>

<bean id="redisManager" class="RedisManager" >
		<property name="url" value="${redis.url}" />
		<property name="password" value="${redis.password}"></property>
</bean>

<bean id="redisSessionDao" class="RedisSessionDao">
		<property name="redisManager" ref="redisManager" />
		<property name="expirationTime" value="442000" /><!-- 秒爲單位 -->
</bean>
相關文章
相關標籤/搜索