单机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问题了。嘿嘿。
以下以验证码为例。
环境现场代码:
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问题了。嘿嘿。
相关文章推荐
- git的使用 - 团队开发
- Maven教程
- 第6周项目1—IT妹子类的设计
- The 7th Zhejiang Provincial Collegiate Programming Contest
- Tixml主页上给的一个遍历方法
- Pku oj 2159 Ancient Cipher(字符串)
- Spring Scope
- I.MX6 Linux 自动获取AR1020 event input节点
- Swift语言中问号 ? 和 感叹号 ! 的作用
- 第五周 22 分数类的雏形
- 游戏中的角色类2
- 线性表的应用2(删除顺序表中的元素)
- 118. Pascal's Triangle
- Coverity代码静态检测工具介绍
- 项目2-带武器的游戏角色
- rk3288的SDK修复cm3218光敏驱动bug
- 获取屏幕的高和宽度
- [BZOJ1070][SCOI2007]修车(费用流)
- 前端开发学习笔记01(大杂烩)
- 第五周 静态成员应用 23