javascript
使用Spring Session和JDBC DataStore进行会话管理
在Web應(yīng)用程序中,用戶會(huì)話管理對于管理用戶狀態(tài)至關(guān)重要。 在本文中,我們將學(xué)習(xí)在集群環(huán)境中管理用戶會(huì)話所遵循的方法,以及如何使用Spring Session以更加簡單和可擴(kuò)展的方式實(shí)現(xiàn)它。
通常在生產(chǎn)環(huán)境中,我們將有多個(gè)服務(wù)器節(jié)點(diǎn),并在它們前面有一個(gè)負(fù)載平衡器,并且所有客戶端流量都將通過負(fù)載平衡器到達(dá)其中一個(gè)服務(wù)器節(jié)點(diǎn)。 因此,我們需要某種機(jī)制來使用戶會(huì)話數(shù)據(jù)可用于集群環(huán)境中的每個(gè)客戶端。
傳統(tǒng)上,我們一直使用以下技術(shù)來管理會(huì)話:
讓我們簡要地看一下這些方法。
1.單節(jié)點(diǎn)服務(wù)器
如果您的應(yīng)用程序不是對企業(yè)至關(guān)重要的服務(wù),那么并發(fā)用戶不會(huì)太多,并且可以接受一些停機(jī)時(shí)間,那么我們可以進(jìn)行單節(jié)點(diǎn)服務(wù)器部署,如下所示:
在此模型中,對于每個(gè)瀏覽器客戶端,將在服務(wù)器上創(chuàng)建會(huì)話對象(對于Java,則為HttpSession ),并且SESSION_ID將被設(shè)置為瀏覽器上的cookie,以標(biāo)識(shí)會(huì)話對象。 但是對于大多數(shù)應(yīng)用程序來說,這種單服務(wù)器節(jié)點(diǎn)部署是不可接受的,因?yàn)槿绻?wù)器關(guān)閉,服務(wù)將完全關(guān)閉。
2.具有粘性會(huì)話的多節(jié)點(diǎn)服務(wù)器
為了使我們的應(yīng)用程序高度可用并滿足更多用戶,我們可以在負(fù)載均衡器后面有多個(gè)服務(wù)器節(jié)點(diǎn)。 在“粘性會(huì)話”方法中,我們將負(fù)載均衡器配置為將所有請求從同一客戶端路由到同一節(jié)點(diǎn)。
在此模型中,將在服務(wù)器節(jié)點(diǎn)中的任何一個(gè)上創(chuàng)建用戶會(huì)話,并將來自該客戶端的所有其他請求發(fā)送到該相同節(jié)點(diǎn)。 但是這種方法的問題是,如果服務(wù)器節(jié)點(diǎn)出現(xiàn)故障,那么該服務(wù)器上的所有用戶會(huì)話都將消失。
3.具有會(huì)話復(fù)制的多節(jié)點(diǎn)服務(wù)器
在此模型中,用戶會(huì)話數(shù)據(jù)將在所有服務(wù)器節(jié)點(diǎn)上復(fù)制,以便可以將任何請求路由到任何服務(wù)器節(jié)點(diǎn)。 即使一個(gè)節(jié)點(diǎn)發(fā)生故障,客戶端請求也可以由另一節(jié)點(diǎn)服務(wù)。
但是會(huì)話復(fù)制需要更好的硬件支持,并涉及某些服務(wù)器特定的配置。
4.具有持久數(shù)據(jù)存儲(chǔ)區(qū)中的會(huì)話數(shù)據(jù)的多節(jié)點(diǎn)服務(wù)器
在此模型中,用戶會(huì)話數(shù)據(jù)將不保存在服務(wù)器的內(nèi)存中,而是將其持久保存到數(shù)據(jù)存儲(chǔ)中并將其與SESSION_ID關(guān)聯(lián)。
此解決方案將獨(dú)立于服務(wù)器,但是每當(dāng)用戶向其會(huì)話中添加一些信息時(shí),我們可能都需要編寫自定義代碼以將會(huì)話數(shù)據(jù)透明地存儲(chǔ)在Persistent數(shù)據(jù)存儲(chǔ)區(qū)中。
這是Spring Session出現(xiàn)的地方。
Spring會(huì)議
Spring Session是方法4的實(shí)現(xiàn),它是將會(huì)話數(shù)據(jù)存儲(chǔ)在持久數(shù)據(jù)存儲(chǔ)區(qū)中。 Spring Session支持RDBMS,Redis,HazelCast,MongoDB等多個(gè)數(shù)據(jù)存儲(chǔ),以透明地保存使用會(huì)話數(shù)據(jù)。 與往常一樣,將Spring Session與Spring Boot一起使用就像添加依賴項(xiàng)和配置少量屬性一樣簡單。
讓我們看看如何在Spring Boot應(yīng)用程序中將Spring Session與JDBC后端存儲(chǔ)一起使用。
https://github.com/sivaprasadreddy/spring-session-samples
步驟1:創(chuàng)建Spring Boot應(yīng)用程序
使用具有Web , Thymeleaf , JPA , H2和Session starters的最新版本(撰寫時(shí)為2.0.0.RC1 )創(chuàng)建SpringBoot應(yīng)用程序。
默認(rèn)情況下,Session入門程序?qū)⑻砑?strong>org.springframework.session:spring-session-core依賴項(xiàng) ,讓我們在使用JDBC后端時(shí)將其更改為spring-session- jdbc 。
步驟2:配置Spring Session屬性
我們可以在application.properties使用spring.session.store類型的屬性配置Spring會(huì)議后端數(shù)據(jù)存儲(chǔ)的類型。
spring.session.store-type=jdbc當(dāng)我們使用H2內(nèi)存數(shù)據(jù)庫時(shí),Spring Session將創(chuàng)建以下表,這些表是通過腳本spring-session- jdbc -2.0.1.RELEASE.jar!/ org / springframework / session / jdbc / schema自動(dòng)存儲(chǔ)會(huì)話數(shù)據(jù)所需的。 -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),則可以進(jìn)行如下配置:
添加MySQL Maven依賴項(xiàng)。
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId> </dependency>為MySQL配置數(shù)據(jù)源屬性:
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表創(chuàng)建。
spring.session.jdbc.initialize-schema=always有了這個(gè)屬性,Spring Session將嘗試使用腳本“ classpath:org / springframework / session / jdbc / schema-@@ platform @@。sql”創(chuàng)建表,因此在本例中,它將使用schema-mysql.sql 。
步驟3:將資料新增至HttpSession
現(xiàn)在,在src / main / resources / templates / index.html中創(chuàng)建一個(gè)簡單的表單。
<!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>讓我們實(shí)現(xiàn)一個(gè)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:/";} }現(xiàn)在,您可以啟動(dòng)應(yīng)用程序并將一些消息添加到HttpSession中,并且可以看到SPRING_SESSION , SPRING_SESSION_ATTRIBUTES表中的行。 默認(rèn)情況下,Spring Session將我們嘗試添加到HttpSession的對象轉(zhuǎn)換為ByteArray并將其存儲(chǔ)在表中。
Spring SecuritySpring會(huì)議
由于SpringBoot的自動(dòng)配置, Spring Session與Spring Security無縫集成。
讓我們將Spring Security添加到我們的應(yīng)用程序中。
在application.properties中添加默認(rèn)用戶憑據(jù),如下所示:
spring.security.user.name=admin spring.security.user.password=secret 現(xiàn)在,如果您嘗試訪問http:// localhost:8080 /,您將被重定向到自動(dòng)生成的登錄頁面。
登錄并查看SPRING_SESSION表中的數(shù)據(jù)后,您可以看到登錄用戶名存儲(chǔ)在PRINCIPAL_NAME列中。
Spring Session如何工作?
Spring Session提供了HttpServletRequest和HttpSession的實(shí)現(xiàn),分別是SessionRepositoryRequestWrapper和HttpSessionWrapper 。 Spring Session提供SessionRepositoryFilter來攔截所有請求,并將HttpServletRequest包裝在SessionRepositoryRequestWrapper中 。
在SessionRepositoryRequestWrapper.getSession(boolean)中,它被重寫以返回HttpSessionWrapper對象,而不是默認(rèn)的HttpSession服務(wù)器實(shí)現(xiàn)。 HttpSessionWrapper使用SessionRepository將會(huì)話信息保存在數(shù)據(jù)存儲(chǔ)中。
SessionRepository接口具有多種管理會(huì)話的方法。
public interface SessionRepository<S extends Session> {S createSession();void save(S session);S findById(String id);void deleteById(String id); }這個(gè)SessionRepository接口由各種類根據(jù)我們使用的后端類型實(shí)現(xiàn)。 在本例中,我們使用的是spring-session-jdbc提供的JdbcOperationsSessionRepository 。
結(jié)論
如您可能已經(jīng)觀察到的,由于Spring Boot的自動(dòng)配置,我們可以通過使用Spring Session進(jìn)行非常少的配置來有效地管理用戶會(huì)話。 如果由于某種原因我們想將后端從JDBC更改為Redis或Hazelcast等,那只是簡單的配置更改,因?yàn)槲覀儾恢苯右蕾囉谌魏蜸pring Session類。
您可以在https://github.com/sivaprasadreddy/spring-session-samples中找到本文的源代碼。
翻譯自: https://www.javacodegeeks.com/2018/02/session-management-using-spring-session-jdbc-datastore.html
總結(jié)
以上是生活随笔為你收集整理的使用Spring Session和JDBC DataStore进行会话管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 外星人台式电脑显卡型号(外星人台式机的显
- 下一篇: 摆脱“空”检查的盛宴:使用JSON Pa