使用Spring Session的原因
在单台Tomcat应用中,通常使用session保存用户的会话数据。
在负载均衡的集群环境下,负载均衡可能将请求分发到不同的服务器上去,在这种情况,需要将有状态的session统一管理起来。
实现Session共享的方案很多,其中一种常用的就是使用Tomcat、Jetty等服务器提供的Session共享功能,将Session的内容统一存储在一个数据库(如MySQL)或缓存(如Redis)中.
本文主要介绍另一种实现Session共享的方案,不依赖于Servlet容器,而是Web应用代码层面的实现,直接在已有项目基础上加入spring Session框架,利用Redis集群做主从复制,利用redis数据库的最终一致性,将session信息存入redis中。
当应用服务器发现session不在本机内存的时候,就去redis数据库中查找,因为redis数据库是独立于应用服务器的数据库,所以可以做到session的共享和高可用。来实现Session统一存储在Redis中。
具体实现
首先导入项目依赖的jar包
<!-- Jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.3.RELEASE</version>
</dependency>
<!-- Spring Session -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
<!-- Apache Commons Pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.4.2</version>
</dependency>
在web.xml中配置Filter: 过滤器使HttpSession不再发挥作用,而是通过过滤器使用redis直接操作Session
<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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
redis配置文件redis.properties:
#redis config
redis.pool.maxTotal=105
redis.pool.maxIdle=10
redis.pool.maxWaitMillis=5000
redis.pool.testOnBorrow=true
#redis 单节点配置
redis.ip=127.0.0.1
redis.port=6379
spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入redis配置 -->
<context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>
<!-- Redis 配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.pool.maxTotal}" />
<property name="maxIdle" value="${redis.pool.maxIdle}" />
<property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}" />
<property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
<!-- redis单节点数据库连接配置 -->
<bean class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.ip}" />
<property name="port" value="${redis.port}" />
<property name="poolConfig" ref="jedisPoolConfig" />
</bean>
</beans>
可以测试一下功能
/**
* Package: com.hqq.web
* User: 何芊芊
* Email: heqianqian1@jd.com
* Date: 2017/11/6
* Time: 18:01
* Description:
*/
@Controller
public class IndexController {
@RequestMapping("/index")
public String index() {
return "home";
}
@RequestMapping("/main")
public String main(HttpServletRequest request) {
HttpSession session = request.getSession();
//从服务器获取session username
String username = (String) session.getAttribute("username");
//如果sessionId存在 用户登录过 就直接登录主页
if (null != username) {
return "main";
} else {
return "login";
}
}
@RequestMapping(value = "/dologin")
public String login(HttpServletRequest request) {
HttpSession session = request.getSession();
String username = request.getParameter("userInput");
session.setAttribute("username", username);
return "redirect:/main";
}
@RequestMapping(path = {"/login"}, method = {RequestMethod.GET})
public String login() {
return "login";
}
}
访问之后查看redis数据库