利用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>
相关文章
相关标签/搜索