datastore

在Web应用程序中,用户会话管理对于管理用户状态至关重要。 在本文中,我们将学习在集群环境中管理用户会话所采用的方法,以及如何使用Spring Session以更简单和可扩展的方式实现该方法。

通常在生产环境中,我们将有多个服务器节点,并在它们前面有一个负载平衡器,并且所有客户端流量都将通过负载平衡器到达其中一个服务器节点。 因此,我们需要某种机制来使用户会话数据可用于集群环境中的每个客户端。
传统上,我们一直使用以下技术来管理会话:

  1. 单节点服务器
  2. 具有负载均衡器和粘性会话的多节点服务器
  3. 具有负载均衡器和会话复制的多节点服务器
  4. 持久性数据存储中具有负载均衡器和会话数据的多节点服务器

让我们简要地看一下这些方法。

1.单节点服务器

如果您的应用程序不是对您的业务至关重要的服务,那么并发用户不会太多,并且可以接受一些停机时间,那么我们可以进行单节点服务器部署,如下所示:


在此模型中,对于每个浏览器客户端,将在服务器上创建会话对象(对于Java,则为HttpSession ),并且SESSION_ID将被设置为浏览器上的cookie,以标识会话对象。 但是对于大多数应用程序来说,这种单服务器节点部署是不可接受的,因为如果服务器关闭,服务将完全关闭。

2.具有粘性会话的多节点服务器

为了使我们的应用程序高度可用并满足更多用户,我们可以在负载均衡器后面有多个服务器节点。 在“粘性会话”方法中,我们将负载均衡器配置为将所有请求从同一客户端路由到同一节点。

在此模型中,将在服务器节点中的任何一个上创建用户会话,并且来自该客户端的所有其他请求将被发送到同一节点。 但是这种方法的问题是,如果服务器节点发生故障,那么该服务器上的所有用户会话都将消失。

3.具有会话复制的多节点服务器

在此模型中,用户会话数据将在所有服务器节点上复制,以便任何请求都可以路由到任何服务器节点。 即使一个节点发生故障,客户端请求也可以由另一节点服务。

但是会话复制需要更好的硬件支持,并涉及某些服务器特定的配置。

4.具有持久数据存储区中的会话数据的多节点服务器

在此模型中,用户会话数据将不保存在服务器的内存中,而是将其持久保存到数据存储中并将其与SESSION_ID关联。

此解决方案将独立于服务器,但是每当用户向其会话中添加一些信息时,我们可能都需要编写自定义代码以将会话数据透明地存储在Persistent数据存储区中。

这是Spring Session出现的地方。

Spring会议

Spring Session是方法4的一种实现,它是将会话数据存储在持久数据存储区中。 Spring Session支持RDBMS,Redis,HazelCast,MongoDB等多个数据存储,以透明地保存使用会话数据。 像往常一样,将Spring Session与Spring Boot一起使用就像添加依赖项和配置少量属性一样简单。
让我们看看如何在Spring Boot应用程序中将Spring Session与JDBC后端存储一起使用。

https://github.com/sivaprasadreddy/spring-session-samples

步骤1:创建Spring Boot应用程序

使用具有WebThymeleafJPAH2Session starters的最新版本(撰写时为2.0.0.RC1 )创建SpringBoot应用程序。
默认情况下,Session入门程序将添加org.springframework.session:spring-session-core依赖项 ,让我们在使用JDBC后端时将其更改为spring-session- jdbc

<dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-jdbc</artifactId>
</dependency>

步骤2:配置Spring Session属性

我们可以在application.properties使用spring.session.store类型的属性配置Spring会议后端数据存储的类型。

spring.session.store-type=jdbc

当我们使用H2内存数据库时,Spring Session将创建以下表,这些表用于通过脚本spring-session- jdbc -2.0.1.RELEASE.jar!/ org / springframework / session / jdbc / schema自动存储会话数据。 -h2.sql

CREATE TABLE SPRING_SESSION (PRIMARY_ID CHAR(36) NOT NULL,SESSION_ID CHAR(36) NOT NULL,CREATION_TIME BIGINT NOT NULL,LAST_ACCESS_TIME BIGINT NOT NULL,MAX_INACTIVE_INTERVAL INT NOT NULL,EXPIRY_TIME BIGINT NOT NULL,PRINCIPAL_NAME VARCHAR(100),CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
);CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);CREATE TABLE SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID CHAR(36) NOT NULL,ATTRIBUTE_NAME VARCHAR(200) NOT NULL,ATTRIBUTE_BYTES LONGVARBINARY NOT NULL,CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
);CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_PRIMARY_ID);

但是,如果我们要使用其他RDBMS(例如MySQL),则可以进行如下配置:

添加MySQL Maven依赖项。

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>

配置MySQL的数据源属性:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=admin

使用spring.session.jdbc.initialize-schema属性启用Spring Session表创建。

spring.session.jdbc.initialize-schema=always

有了这个属性,Spring Session将尝试使用脚本“ classpath:org / springframework / session / jdbc / schema-@@ platform @@。sql”创建表,因此在本例中,它将使用schema-mysql.sql

步骤3:将资料新增至HttpSession

现在,在src / main / resources / templates / index.html中创建一个简单的表单。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Spring Session + JDBC Demo</title>
</head>
<body><div><form th:action="@{/messages}" method="post"><textarea name="msg" cols="40" rows="4"></textarea><input type="submit" value="Save"/>
</form></div><div><h2>Messages</h2><ul th:each="m : ${messages}"><li th:text="${m}">msg</li></ul></div></body>
</html>

让我们实现一个Controller,以将消息添加到HttpSession并显示它们。

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;@Controller
public class MessagesController
{@GetMapping("/")public String index(Model model, HttpSession session) {List<String> msgs = (List<String>) session.getAttribute("MY_MESSAGES");if(msgs == null) {msgs = new ArrayList<>();}model.addAttribute("messages", msgs);return "index";}@PostMapping("/messages")public String saveMessage(@RequestParam("msg") String msg, HttpServletRequest request) {List<String> msgs = (List<String>) request.getSession().getAttribute("MY_MESSAGES");if(msgs == null) {msgs = new ArrayList<>();request.getSession().setAttribute("MY_MESSAGES", msgs);}msgs.add(msg);return "redirect:/";}
}

现在,您可以启动应用程序并将一些消息添加到HttpSession中,并且可以看到SPRING_SESSIONSPRING_SESSION_ATTRIBUTES表中的行。 默认情况下,Spring Session将我们尝试添加到HttpSession的对象转换为ByteArray并将其存储在表中。

Spring Security的Spring会议

由于SpringBoot的自动配置, Spring SessionSpring Security无缝集成。
让我们将Spring Security添加到我们的应用程序中。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>

application.properties中添加默认用户凭据,如下所示:

spring.security.user.name=admin
spring.security.user.password=secret

现在,如果您尝试访问http:// localhost:8080 /,将被重定向到自动生成的登录页面。
登录并查看SPRING_SESSION表中的数据后,您可以看到登录用户名存储在PRINCIPAL_NAME列中。

Spring Session如何工作?

Spring Session提供了HttpServletRequestHttpSession的实现,分别是SessionRepositoryRequestWrapperHttpSessionWrapper 。 Spring Session提供SessionRepositoryFilter来拦截所有请求,并将HttpServletRequest包装在SessionRepositoryRequestWrapper中

SessionRepositoryRequestWrapper.getSession(boolean)中,它被重写以返回HttpSessionWrapper对象,而不是默认的HttpSession服务器实现。 HttpSessionWrapper使用SessionRepository将会话信息保存在数据存储中。

SessionRepository接口具有多种管理会话的方法。

public interface SessionRepository<S extends Session>
{S createSession();void save(S session);S findById(String id);void deleteById(String id);
}

这个SessionRepository接口由各种类根据我们使用的后端类型实现。 在我们的例子中,我们使用的是spring-session-jdbc提供的JdbcOperationsSessionRepository

结论

正如您可能已经观察到的,由于Spring Boot的自动配置,我们可以通过使用Spring Session进行非常少的配置来有效地管理用户会话。 如果由于某种原因我们想将后端从JDBC更改为Redis或Hazelcast等,那只是简单的配置更改,因为我们不直接依赖于任何Spring Session类。

您可以在https://github.com/sivaprasadreddy/spring-session-samples中找到本文的源代码。

翻译自: https://www.javacodegeeks.com/2018/02/session-management-using-spring-session-jdbc-datastore.html

datastore

datastore_使用Spring Session和JDBC DataStore进行会话管理相关推荐

  1. 使用Spring Session和JDBC DataStore进行会话管理

    在Web应用程序中,用户会话管理对于管理用户状态至关重要. 在本文中,我们将学习在集群环境中管理用户会话所遵循的方法,以及如何使用Spring Session以更加简单和可扩展的方式实现它. 通常在生 ...

  2. Spring Security +Spring Session Redis+JJWT

    重要提示 这样集成弄完一波后,导致Spring Security并发控制并没有生效,请大佬们慎重参考下面内容. 问题 希望使用Spring Security对Spring Boot进行保护,并且,使用 ...

  3. 次世代的会话管理项目 Spring Session

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文来自云+社区翻译社,由Tnecesoc编译. 会话管理一直是 Java 企业级应用的重要部分.不过在很长的一段时间里,这一部分都被我们认 ...

  4. Spring Session使用

    一.session的处理方式 参考本人这篇文章 二.spring session使用的session管理方式 就是Session集中管理的方式: 优点:可靠性高,减少Web服务器的资源开销. 缺点:实 ...

  5. Session会话管理

    会话管理 Web会话管理概述 常见的Web应用会话管理方式 基于Server端的Session的管理方式 基于Cookie的Session的管理方式 Cookie与Session最大的区别 Cooki ...

  6. Spring Session Management – Spring Session JDBC

    Spring Session Module provides APIs and implementation for managing user session in a web applicatio ...

  7. 在spring MVC项目中集成Spring session redis (使用spring session框架,redis作为存储缓存)...

    2019独角兽企业重金招聘Python工程师标准>>> 1.为项目增加以来  pom.xml中使用 <!-- spring session 单点登录 --> //本项目使 ...

  8. Re:从零开始的Spring Session(二)

    上一篇文章介绍了一些Session和Cookie的基础知识,这篇文章开始正式介绍Spring Session是如何对传统的Session进行改造的.官网这么介绍Spring Session: Spri ...

  9. Spring Session实战4

    然后来到Spring Session的配置文件,我们增加一个bean,id就是这个类defaultCookieSerializer,class就是org.springframework.session ...

最新文章

  1. python判断二叉树是否为平衡二叉树
  2. spring cloud集成 consul源码分析
  3. python装饰器简单理解的小demo
  4. 10分钟了解JSON Web令牌(JWT)
  5. rabbitmq 拉取消息太慢_面试官:消息队列这些我都要问
  6. graphpad细胞增殖曲线_肿瘤干细胞?居然被这两个新加坡人轻松干掉了?
  7. pcl的初步使用(ROS)
  8. 如何用python写个人专属群聊提醒小助手?
  9. ArcGIS案例学习笔记2_2_等高线生成DEM和三维景观动画
  10. 申请了:苹果已经在测试“毫米波”5G技术
  11. 【Linux】02 用户和权限
  12. 线上问题:大事务问题
  13. configure: error: --with-openssl was given but OpenSSL could not be detected 解决方法(Curl交叉编译到Arm板)
  14. 2007年考研时间安排表
  15. 双代号网络图如何用计算机画,怎么画双代号网络图,双代号网络图的绘制规则和步骤...
  16. 服务器怎么预防常见的网络攻击
  17. python对财务的作用_学习Python对财务工作者有哪些用途?
  18. 50. 从暗通道先验去雾到海底图像修复-三维重建辅助计算摄影
  19. 阿里云云效流水线教程
  20. python爬取猫眼电影数据

热门文章

  1. [APIO2016] 划艇(dp + 组合数 + 前缀和优化)
  2. YBTOJ洛谷P2223:软件开发(费用流)
  3. AT4518-[AGC032C]Three Circuits【欧拉回路】
  4. Codeforces Round #674 (Div. 3)
  5. 糊涂的教授(2015特长生 T3)
  6. 【bfs】WJ的逃离
  7. Spark入门(十七)之单表关联
  8. Spring MVC请求url无效问题思考
  9. 一文搞懂 Java 线程中断
  10. SQL正在击败NoSQL,这对未来的数据意味着什么