任何一种技术的出现,都是来解决特定的问题的!html
本篇开始学习Spring-Session相关的一些知识学习整理,让咱们开始吧!html5
HttpSession是经过Servlet容器进行建立和管理的,在单机环境中。经过Http请求建立的Session信息是存储在Web服务器内存中,如Tomcat/Jetty。java
假如当用户经过浏览器访问应用服务器,session信息中保存了用户的登陆信息,而且session信息没有过时失,效那么用户就一直处于登陆状态,能够作一些登陆状态的业务操做!
nginx
可是如今不少的服务器都采用分布式集群的方式进行部署,一个Web应用,可能部署在几台不一样的服务器上,经过LVS或者Nginx等进行负载均衡(通常使用Nginx+Tomcat实现负载均衡)。此时来自同一用户的Http请求将有可能被分发到不一样的web站点中去(如:第一次分配到A站点,第二次可能分配到B站点)。那么问题就来了,如何保证不一样的web站点可以共享同一份session数据呢?git
假如用户在发起第一次请求时候访问了A站点,并在A站点的session中保存了登陆信息,当用户第二次发起请求,经过负载均衡请求分配到B站点了,那么此时B站点可否获取用户保存的登陆的信息呢?答案是不能的,由于上面说明,Session是存储在对应Web服务器的内存的,不能进行共享,此时Spring-session就出现了,来帮咱们解决这个session共享的问题!github
简单点说就是请求http请求通过Filter职责链,根据配置信息过滤器将建立session的权利由tomcat交给了Spring-session中的SessionRepository,经过Spring-session建立会话,并保存到对应的地方。web
实际上实现Session共享的方案不少,其中一种经常使用的就是使用Tomcat、Jetty等服务器提供的Session共享功能,将Session的内容统一存储在一个数据库(如MySQL)或缓存(如Redis,Mongo)中,redis
而上面说的使用Nginx也能够,使用ip_hash策略。
【Nginx】实现负载均衡的几种方式
在使用Nginx的ip_hash策略时候,每一个请求按访问ip的hash结果分配,这样每一个访客固定访问一个后端服务器,也能够解决session的问题。spring
Spring会话提供了与HttpSession的透明集成,容许以应用程序容器(即Tomcat)中性的方式替换HttpSession,可是咱们从中获得了什么好处呢?数据库
RESTful api——Spring会话容许在header中提供会话id以使用RESTful api。
Spring Session & WebSockets的完美集成。
整个项目的总体骨架:
本次只讲解xml配置方式,javaConfig配置能够参考官方文档:Spring Java Configuration
本次项目须要用户Nginx和Redis,若是没有配置Nginx的请看这里: Windows上Nginx的安装教程详解
没有配置Redis的请看这里:Redis——windows环境安装Redis和Redis sentinel部署教程
配置好了上面的环境,后下面开始正式的Spring-session搭建过程了!
首先新建一个Maven的Web项目,新建好以后在pom文件中添加下面的依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.spring</groupId> <artifactId>learn-spring-session</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>First Learn Spring Session</name> <properties> <jdk.version>1.7</jdk.version> <spring.version>4.3.4.RELEASE</spring.version> <spring-session.version>1.3.1.RELEASE</spring-session.version> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> <version>${spring-session.version}</version> <type>pom</type> </dependency> <dependency> <groupId>biz.paluch.redis</groupId> <artifactId>lettuce</artifactId> <version>3.5.0.Final</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> </dependencies> </project>
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring/*xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--DelegatingFilterProxy将查找一个Bean的名字springSessionRepositoryFilter丢给一个过滤器。为每一个请求 调用DelegatingFilterProxy, springSessionRepositoryFilter将被调用--> <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> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
在resources 下面新建一个xml,名词为 application-session.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-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:annotation-config/> <!--建立一个Spring Bean的名称springSessionRepositoryFilter实现过滤器。 筛选器负责将HttpSession实现替换为Spring会话支持。在这个实例中,Spring会话获得了Redis的支持。--> <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/> <!--建立了一个RedisConnectionFactory,它将Spring会话链接到Redis服务器。咱们配置链接到默认端口(6379)上的本地主机!--> <bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/> </beans>
新建 LoginServlet.java
@WebServlet("/login") public class LoginServlet extends HttpServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; request.getSession().setAttribute("testKey", "742981086@qq.com"); request.getSession().setMaxInactiveInterval(10*1000); response.sendRedirect(request.getContextPath() + "/session"); } }
新建 SessionServlet.java
@WebServlet("/session") public class SessionServlet extends HttpServlet { @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; System.out.println(request.getRemoteAddr()); System.out.print(request.getRemoteHost() + " : " + request.getRemotePort()); String sesssionID = request.getSession().getId(); System.out.println("-----------tomcat2---sesssionID-------" + sesssionID); String testKey = (String)request.getSession().getAttribute("testKey"); System.out.println("-----------tomcat2-testKey-------" + testKey); PrintWriter out = null; try { out = response.getWriter(); out.append("tomcat2 ---- sesssionID : " + sesssionID); out.append("{\"name\":\"dufy2\"}" + "\n"); out.append("tomcat2 ----- testKey : " + testKey + "\n"); }catch (Exception e){ e.printStackTrace(); }finally { if(out != null){ out.close(); } } } }
Nginx的配置,轮询方式:
#user nobody; worker_processes 1; events{ worker_connections 1024; } http{ upstream myproject { server 127.0.0.1:8888; server 127.0.0.1:9999; } server { listen 8080; server_name localhost; location / { proxy_pass http://myproject; } } }
将上面搭建好的项目放入两个Tomcat中,分别启动。使用Nginx负载均衡均验证Session是否共享成功!
tomcat1 : http://localhost:8888/
tomcat2 : http://localhost:9999/
访问 http://localhost:8080/ 能够看到,每次刷新页面,请求都分发到不一样的Tomcat里面,如图
而后使用 http://localhost:8080/login 看到地址栏重定向到/session .发现浏览器返回了数据,进入tomcat2中,而后再次刷新请求进入了tomcat1,发现tomcat2中和tomcat1 sessionId同样,而且在tomcat1中存的testKey,在Tomcat2中也能够获取,不只SessionId能够共享,其余一些数据也能够进行共享!
如何在Redis中查看Session数据,可使用命令,或者在Windows的RedisDesktopManager中查看!
key的简单介绍说明:
# 存储 Session 数据,数据类型hash Key:spring:session:sessions:XXXXXXX # Redis TTL触发Session 过时。(Redis 自己功能),数据类型:String Key:spring:session:sessions:expires:XXXXX #执行 TTL key ,查看剩余生存时间 #定时Job程序触发Session 过时。(spring-session 功能),数据类型:Set Key:spring:session:expirations:XXXXX
验证成功!
Spring-Session在实际的项目中使用仍是比较普遍的,本次搭建采用最简单的配置,基本都是采用官方文档中默认的方式,由于是入门的教程就没有写的很复杂,后面慢慢深刻!期待后续的教程吧!
使用Spring Session和Redis解决分布式Session跨域共享问题57406162
学习Spring-Session+Redis实现session共享
【第一篇】Spring-Session实现Session共享入门教程
【第二篇】Spring-Session实现Session共享Redis集群方式配置教程【更新中...请期待...】
【第三篇】Spring-Session实现Session共享实现原理以及源码解析【更新中...请期待...】
本系列的源码下载地址:learn-spring-session-core
备注: 因为本人能力有限,文中如有错误之处,欢迎指正。
谢谢你的阅读,若是您以为这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到!祝你天天开心愉快!