使用Spring Session和JDBC 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 SecuritySpring会议

由于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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/347762.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面向对象(3)--类的成员方法

基本格式&#xff1a; 修饰符 返回值类型 方法名&#xff08;参数类型 形参1, 参数类型 形参2, …&#xff09;&#xff5b;方法体程序代码;return 返回值; &#xff5d;修饰符&#xff1a;public,缺省,private, protected等 返回值类型&#xff1a; ①没有返回值&#xff1a…

java 线程安全的单例_线程安全的单例模式的几种实现

单例模式是常见的设计模式之一&#xff1a;目的是节省内存&#xff0c;限制了实例的个数&#xff1b;有利于java GC回收机制。单例模式的三个好处&#xff1a;1.控制资源的使用&#xff0c;通过线程同步来控制资源的并发访问2.控制实例的产生个数&#xff0c;来达到节约资源的目…

Java面向对象(3.1)--方法的重载,可变个数的形参,值传递机制,递归

重载 在同一个类中&#xff0c;允许存在一个以上的同名方法&#xff0c;只要它们的参数个数或者参数 类型不同即可。 与返回值类型无关&#xff0c;只看参数列表&#xff0c;且参数列表必须不同。(参数个数或参数类 型或者多个参数时参数类型顺序)。调用时&#xff0c;根据方…

python统计图像直方图_计算机视觉7-像素点直方图统计、掩膜图像

1.灰度图的直方图(1)调用库import cv2import matplotlib.pyplot as pltimport numpy as np #创建掩膜时需要(2)绘图-方法1imgcv2.imread(F:cat.jpg,0)plt.hist(img.ravel(),256,[0,256])plt.show()plt.hist是一个画直方图的命令&#xff1b;img.ravel()可以将图片转化成一维数组…

计算机二级web题目(8.1)--综合选择题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1、一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再…

java支持的数据类型有哪些_Java支持的数据类型有哪些?什么时候自动装拆箱?...

java中的8种基本数据类型&#xff1a;boolean byte char short int float double long自动拆装箱的问题引入&#xff1a;由于在一开始学习java的时候&#xff0c;”万物皆对象“这种面向对象的看问题方式&#xff0c;时刻围绕在脑海中。因为静态的变量和基本数据类型不属于对象…

Java面向对象(4)--封装和隐藏

Java中通过将数据声明为私有的(private)&#xff0c;再提供公共的&#xff08;public&#xff09;方法:获取getXxx()和设置setXxx()实现对该属性的操作&#xff0c;以实现下述目的&#xff1a; ①隐藏一个类中不需要对外提供的实现细节。 ②使用者只能通过事先定制好的方法来访…

跑来跑去:假人与AWS Lambda的第一次接触

一切始于埃及人在一个木框上滑动几块大理石以简单的算术使其大脑放松。 或许是希腊人发明了Antikythera机制来追踪行星的运动至每千年2度的精度 。 无论哪种方式&#xff0c;计算都已经走了很长一段路&#xff1a;查尔斯巴贝奇的分析引擎 &#xff0c;艾伦图灵的Enigma-breaker…

(2.1)HarmonyOS鸿蒙Ability创建,XML和Java页面布局UI

鸿蒙UI中&#xff0c;提供了两种编写布局的方式&#xff1a; ①在XML中声明UI布局 ②在Ability代码中直接通过Java创建布局 这两种方式创建出的布局没有本质差别&#xff0c;但是XML方式较为方便简单。 在XML文件中布局 与HTMLCSS的前端布局类似&#xff0c;通过使用不同类型的…

cstring越界_CString和char*的转换

方法1、const char*转换CString str;const char *p(const char*)str;const char *表示你对字符串只读&#xff0c;所以这时候可以直接获取。方法2、使用强制类型转换如需要对字符串写权限&#xff0c;则&#xff1a;CString str;char *p (char *)(const char *)str;方法3、使用…

使用Azure Blob存储托管Maven工件

如果您使用Microsoft Azure并且将Java用于项目&#xff0c;则Azure Blob存储是托管团队工件的理想场所。 它很容易设置&#xff0c;而且很便宜。 如果您对它们的功能不特别感兴趣&#xff0c;那么它比设置现有存储库选项&#xff08;jfrog&#xff0c;nexus&#xff0c;archiv…

(2.2)HarmonyOS鸿蒙页面跳转

本文页面跳转基于《Ability创建子页面布局》所存在的两个页面MainAbility和SecondAbility。 在MainAbilitySlice中进行代码编写 package com.example.myapplication.slice;import com.example.myapplication.ResourceTable; import ohos.aafwk.ability.AbilitySlice; import o…

java 将换行代替_Java批量将文件中的段落替换成空格,根据指定分隔符换行(SQL示例)...

我的需求是SQL文件中有成千的类似数据&#xff0c;我要将它们进行转换格式&#xff0c;如下图第一步&#xff1a;将字符段楼替换&#xff0c;使用word排版把数据拷贝到word中&#xff0c;使用特殊字符替换点击全部替换&#xff0c;替换之后如下图&#xff0c;这时候它是一串很长…

wicket_Wicket模型的干净方法

wicketApache Wicket Web框架的核心概念之一是模型和IModel作为其编程接口。 Wicket组件严重依赖模型&#xff0c;这使它们成为体系结构的重要组成部分。 Apache Wicket是一个有状态框架&#xff0c;将页面及其组件存储到通常位于HTTP会话中的页面存储中。 组件根据模型的内容创…

计算机二级web题目(8.2)--基本操作题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1.在考生文件夹下的Web1目录中&#xff0c;存有1.htm文件&#xff0c;该文件不完…

java的选项板_CAD工具选项板的介绍以及新建方法

CAD中的工具选项板是【工具选项板】窗口中选项卡形式的区域&#xff0c;不但能提供组织、共享和放置块及填充图案的很有效的方法&#xff0c;还能够包含由第三方开发人员提供的自定义工具。【工具选项板】窗口包括注释、建筑、机械、电力、图案填充和土木工程等选项板。当需要向…

摆脱“空”检查的盛宴:使用JSON Patch正确执行PATCH

今天&#xff0c;我们将就REST&#xff08;ful&#xff09;服务和API进行一次对话&#xff0c;更准确地说&#xff0c;围绕许多经验丰富的开发人员正在努力解决的一个独特主题。 为了使事情更直观&#xff0c;我们将讨论Web API&#xff0c;其中REST&#xff08;ful&#xff09…

Java面向对象(5)--类的成员构造器(构造方法)

创建对象&#xff1b;给对象进行初始化。 ①隐式无参构造器&#xff08;没有创建时&#xff0c;系统默认提供的&#xff09; ②显式定义一个或多个构造器&#xff08;无参、有参&#xff09; 基本格式 修饰符 类名 (参数列表) {初始化语句&#xff1b; }特征 ①它具有与类相…

java单链表 提供增删改查_java实现单链表增删改查的实例代码详解

package 数据结构算法.链表;/**定义节点* 链表由节点构成*/public class node {private e e; //数据dataprivate node next; //指向下一个节点public node() {}public node(e e) {this.e e;}public node getnext() {return next;}public void setnext(node next) {this.next …

Java面向对象(6)--this关键字使用

this可理解为:当前对象或当前正在创建的对象 ①在类的方法中&#xff0c; 我们可以使用"this.属性"或"this.方法"的方式&#xff0c;调用当前对象属性或方法。通常情况下&#xff0c;我们都选择省略"this."。特殊情况下&#xff0c;如果方法的形…