利用Redis共享Tomcat中的Session

本文介绍了两种实现Tomcat集群中Session共享的方法:通过替换Tomcat的sessionManager使用Redis进行集中管理,以及在Spring和Apache Shiro框架下,通过继承Shiro的AbstractSessionDAO并利用Redis实现Session的持久化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

想要做Tomcat集群,其中需要解决的一个问题就是多个Tomcat中session的共享。共享的方法有很多种,比如使用Tomcat自带的session复制,使用数据库等。这里一些介绍我使用过的方法。

1.替换Tomcat的sessionManager

这种方法实现起来比较容易,但是需要改动每个Tomcat服务器的配置。对于Tomcat6和7,可以使用tomcat-redis-session-manager库来实现,对于Tomcat8以及8以上的版本,可以搜索对应的库。

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

库的介绍里有详细的使用方法,这里再简单列一下:

  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标签之前

  2. 将以下依赖包拷贝到  TOMCAT_BASE/lib  目录
  • tomcat-redis-session-manager-VERSION.jar
  • jedis-2.5.2.jar
  • commons-pool2-2.2.jar

重启Tomcat后生效。

 

如果项目中使用了Spring和Apache Shiro,可以使用下面的方法。

2.继承Shiro的AbstractSessionDAO

序列化工具示例:

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示例:

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>

 

转载于:https://my.oschina.net/u/1756290/blog/760340

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值