您的位置:首页 > 其它

单机session共享问题的解决

2016-04-05 18:50 549 查看
在前台验证码使用servlet写的或者登录数据放入session中,但是当项目要发生产环境的话会产生该问题,原因是session只存在于单机如果多台服务器的话,在登录或者验证码等问题从session获取值时报错。
以下以验证码为例。
环境现场代码:
1、web.xml中配置

<!-- 配置验证码servlet -->
<servlet>
<servlet-name>validateCode</servlet-name>
<servlet-class>com.msok.insure.servlet.ValidateCodeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>validateCode</servlet-name>
<url-pattern>/ValidateCodeServlet.do</url-pattern>
</servlet-mapping>
<servlet>

2、controller中servlet类-源码 http://note.youdao.com/share/?id=319bebf8110c29152515892b655db0ff&type=note
3、可以采用什么方式避免呢有以下几种想法

第一种想法:可以用分布式缓存

分布式环境下的session需要解决如下几个问题:

1.会话数据更新的同步

2.会话过期的同步

3.会话删除的同步

4.会话access的同步

第二种想法:Tomcat+memcached/redis

将session信息保存到缓存中生成唯一的key-value,然后在cookie中保存key,用户请求时通过key去缓存中获取session信息

第三种想法:

1.不使用session,session中的数据采用加密存放到cookie中

2.前段负载均衡按照请求IP分流到appserver,同一iP的请求分发到同一个appserver,防止session的分布式问题。

第四种想法:

不用session而是自己定义新的cookie来实现(如user_id) 客户端存状态,服务器端可以把数据放到如memcached、mysql内存表等中;

Cookie Based或者用session数据统一放到一个redis里面

第五种想法:

使用Session Sticky或者Session
Replication
自己写的解决局部问题的方式(Springmvc+Redis配置好的--maven管理的)
ApplicationContext applicationContext=(ApplicationContext) req.getSession().getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext.ROOT");
RedisTemplate redisTemplate =(RedisTemplate)applicationContext.getBean("redisTemplate");
如果多处用到了session而且为了减少最少的改动且提高复用性请往下看
相关环境配置
1首先,我们需要引入基本的jar包。maven中的基本引用如下:

  <dependency>

<groupId>org.springframework.data</groupId>

<artifactId>spring-data-redis</artifactId>

<version>1.4.2.RELEASE</version>

</dependency>

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

<version>2.6.2</version>

</dependency>

2配置下springmvc.xml

2-1配置jedisPoolConfig

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">

<property name="maxTotal" value="${redis.pool.maxTotal}" /><!--
maxActive -->
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="minIdle" value="${redis.pool.minIdle}" />
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>

2-2配置jedisConnectionFactory

<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}" />
<property name="port" value="${redis.port}" />
<property name="timeout" value="${redis.timeout}" />
<property name="usePool" value="${redis.usePool}" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>

2-3配置stringRedisSerializer
<bean id="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer" />
2-4配置缓存机制

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">

<property name="connectionFactory" ref="jedisConnectionFactory"/>

<property name="keySerializer" ref="stringRedisSerializer"/>

<property name="hashKeySerializer" ref="stringRedisSerializer"/></bean>

3、redis.properties

#\u6d4b\u8bd5
redis.host=172.30.9.12
#redis\u7aef\u53e3
redis.port=6908
#redis\u8fde\u63a5\u6c60\u6700\u5927\u503c
redis.pool.maxTotal=300
#redis\u8fde\u63a5\u6700\u5927\u7a7a\u95f2\u503c
redis.pool.maxIdle=20
#redis\u8fde\u63a5\u6700\u5c0f\u7a7a\u95f2\u503c
redis.pool.minIdle=5
#redis\u83b7\u53d6\u8fde\u63a5\u65f6\u662f\u5426\u9a8c\u8bc1\u53ef\u7528\u6027
redis.pool.testOnBorrow=true
#redis\u8fde\u63a5\u8d85\u65f6\u65f6\u95f4
redis.timeout=5000
#\u662f\u5426\u4f7f\u7528\u8fde\u63a5\u6c60\u7ba1\u7406\u8fde\u63a5
redis.usePool=true

在web.xml中配置(最终达到高效性,复用性、推荐)将所有的session数据都统一放入redis缓存中,依然照常可以使用session

<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.msok.insure.utils.RedisSessionFilter</filter-class>
<init-param>
<param-name>sessionId</param-name>
<!-- cookie name, cookie value 是真实的sessionId -->
<param-value>insure_platform_sid</param-value>
</init-param>
<init-param>
<param-name>cookieDomain</param-name>
<param-value></param-value>
</init-param>
<init-param>
<param-name>cookiePath</param-name>
<param-value>/</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/*</url-pattern>
<!-- <url-pattern>*.shtml</url-pattern> -->
</filter-mapping>

-------------------------------------------------配置的sessionFilter类 代码如下---------------------------------

package com.msok.insure.utils;

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpServletResponseWrapper;

import javax.servlet.http.HttpSession;

/**

* Session数据存到Redis

*

*/

public class RedisSessionFilter implements Filter {

private String sessionId = "msok_sid";

private String cookieDomain = "";

private String cookiePath = "/";

private int timeoutMinute = 30;

@Override

public void init(FilterConfig filterConfig) throws ServletException {

this.sessionId = filterConfig.getInitParameter("sessionId");

this.cookieDomain = filterConfig.getInitParameter("cookieDomain");

if (this.cookieDomain == null) {

this.cookieDomain = "";

}

this.cookiePath = filterConfig.getInitParameter("cookiePath");

if (this.cookiePath == null || this.cookiePath.length() == 0) {

this.cookiePath = "/";

}

String timeoutMinute = filterConfig.getInitParameter("timeoutMinute");

if(timeoutMinute != null && !timeoutMinute.isEmpty()){

try{

int timeTmp = Integer.parseInt(timeoutMinute);

if(timeTmp > 0){

this.timeoutMinute = timeTmp;

}

} catch(Exception e){

}

}

}

@Override

public void doFilter(ServletRequest servletRequest,

ServletResponse servletResponse, FilterChain filterChain)

throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servletRequest;

HttpServletResponse response = (HttpServletResponse) servletResponse;

// 清除url链接上的jsessionid

if (request.isRequestedSessionIdFromURL()) {

HttpSession session = request.getSession();

if (session != null)

session.invalidate();

}

Cookie cookies[] = request.getCookies();

Cookie sCookie = null;

String sid = "";

if (cookies != null && cookies.length > 0) {

for (int i = 0; i < cookies.length; i++) {

sCookie = cookies[i];

if (sCookie.getName().equals(sessionId)) {

sid = sCookie.getValue();

}

}

}

if (sid == null || sid.length() == 0) {

sid = java.util.UUID.randomUUID().toString();

Cookie mycookies = new Cookie(sessionId, sid);

mycookies.setMaxAge(-1);

// mycookies.setHttpOnly(true);

if (this.cookieDomain != null && this.cookieDomain.length() > 0) {

mycookies.setDomain(this.cookieDomain);

}

mycookies.setPath(this.cookiePath);

response.addCookie(mycookies);

}

// 去除url中的jsessionid

HttpServletResponseWrapper wrappedResponse = new HttpServletResponseWrapper(

response) {

@Override

public String encodeRedirectUrl(String url) {

return url;

}

@Override

public String encodeRedirectURL(String url) {

return url;

}

@Override

public String encodeUrl(String url) {

return url;

}

@Override

public String encodeURL(String url) {

return url;

}

};

filterChain.doFilter(new HttpServletRequestRedisWrapper(sid, request,timeoutMinute),

wrappedResponse);

}

@Override

public void destroy() {

// TODO Auto-generated method stub

}

}

这样就再也不用担心单机共享session问题了。嘿嘿。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: