HttpSession是通过servlet容器创建的,保存在tomcat等容器内存中。但是分布式集群的应用中,利用nginx做负载,同一个请求可能会被分配到不同的容器中,那么如何保证不同容器之间session的共享呢?spring为我们提供了解决方法。就是通过filter封装HttpServletRequestWrapper,重写getSession(),将session放到redis或者Memcached,取的时候从redis/memcached中取。其实就是把session放到一个公共地方,这样不同的容器就都可以使用同一个session了。
实现例子:
1. 架包:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>1.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
我是把spring-mvc的架包全部拿过来了。其中spring-session-data-redis就是spring将session放入redis的架包,还需要java.servlet-api 因为会用到HttpServlet等类,scope还要设置成provided,因为等等部署到tomcat中会和tomcat的javax架包冲突,不知道的请移步SCOPE。
2. web.xml
<!-- 封装session的filter -->
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- servlet -->
<servlet>
<servlet-name>loginServlet</servlet-name>
<servlet-class>com.tang.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginServlet</servlet-name>
<url-pattern>/action/login</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>indexServlet</servlet-name>
<servlet-class>com.tang.servlet.IndexServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>indexServlet</servlet-name>
<url-pattern>/action/index</url-pattern>
</servlet-mapping>
第一个filter放最前面,因为这个filter是是实现session存入redis的
3. appicationContext.xml
<context:component-scan base-package="com.tang" />
<bean id="redisHttpSessionConfiguration"
class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
<property name="maxInactiveIntervalInSeconds" value="1800"/>
</bean>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="100" />
<property name="maxIdle" value="10" />
</bean>
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy">
<property name="hostName" value="127.0.0.1"/>
<property name="port" value="6379"/>
<property name="timeout" value="3000"/>
<property name="usePool" value="true"/>
<property name="poolConfig" ref="jedisPoolConfig"/>
</bean>
第一个bean就是实现session放入redis,maxInactiveIntervalInSeconds超时时间,默认1800,下面几个bean是redis的一些基本配置。
4. Servlet
LoginServlet:
public class LoginServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 设置session
// 将session放入redis中
req.getSession().setAttribute("mysession", "tangxw");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
this.doGet(req, resp);
}
}
IndexServlet:
public class IndexServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 从redis中取出session
String mysession = (String) req.getSession().getAttribute("mysession");
System.out.println("mysession = " + mysession);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
this.doGet(req, resp);
}
}
5. 测试
mvn package打包项目,把war放到tomcat下,启动redis,启动tomcat,访问:http://localhost:8082/action/login,建立session,放入redis中。我们看一下redis中的有没有放session。
可以看到redis中已经保存了我们的session了。
然后我们将maven打包的war放到另一台tomcat中,启动tomcat,访问:http://localhost:8081/action/index,可以发现能打印session(mysession) 的值,说明session确实共享了。
以上就是通过spring-session-data-redis来实现session共享。
参考文章:http://blog.csdn.net/patrickyoung6625/article/details/45694157