溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring中Session的作用是什么

發(fā)布時間:2021-06-21 10:10:31 來源:億速云 閱讀:499 作者:chen 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Spring中Session的作用是什么”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Spring中Session的作用是什么”吧!

目錄
  • Session

  • Session常用解決方案

  • Spring-Session

    • 測試代碼

    • 基于數(shù)據(jù)庫的Spring-Session

    • 基于Redis的Spring-Session

  • 總結(jié)

    Session

    Http協(xié)議是無狀態(tài)的,這樣對于服務(wù)端來說,沒有辦法區(qū)分是新的訪客還是舊的訪客。但是,有些業(yè)務(wù)場景,需要追蹤用戶多個請求,此時就需要Session。關(guān)于session的百度百科session

    Session:在計算機(jī)中,尤其是在網(wǎng)絡(luò)應(yīng)用中,稱為“會話控制”。Session對象存儲特定用戶會話所需的屬性及配置信息。這樣,當(dāng)用戶在應(yīng)用程序的Web頁之間跳轉(zhuǎn)時,存儲在Session對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。當(dāng)用戶請求來自應(yīng)用程序的 Web頁時,如果該用戶還沒有會話,則Web服務(wù)器將自動創(chuàng)建一個 Session對象。當(dāng)會話過期或被放棄后,服務(wù)器將終止該會話

    核心特點:

    1. 服務(wù)端存儲

    2. 會過期

    Session常用解決方案

    對于Session的常用解決方案,可以劃分為三種。

    借助負(fù)載均衡設(shè)備或者模塊,將指定的Session始終路由到同一臺機(jī)器即可,如Nginx。

    • 副本復(fù)制方式

    利用服務(wù)器節(jié)點間的副本復(fù)制方式,保證集群所有節(jié)點擁有的Session數(shù)據(jù)一致。

    • 集中存儲方式

    引入第三方存儲,將Session數(shù)據(jù)集中存儲到外部存儲中,如Redis或者數(shù)據(jù)庫等。

    本文介紹的Spring-Session是采用第三種,集中存儲的方式。

    Spring-Session

    核心組成模塊

    • Spring Session Core

    提供Spring Session核心的功能和API

    • Spring Session Data Redis

    提供基于Redis的SessionRepository以及配置

    • Spring Session JDBC

    提供基于關(guān)系型數(shù)據(jù)庫的SessionRepository以及配置

    • Spring Session Hazelcast

    提供基于Hazelcast的SessionRepository以及配置

    測試代碼

    controller提供三個接口,分別對應(yīng)Session的獲取、保存和清理

    @GetMapping("/")
    public String process(Model model, HttpSession session) {
      @SuppressWarnings("unchecked")
      List<String> messages = (List<String>) session.getAttribute("springSession");
    
      if (messages == null) {
        messages = new ArrayList<>();
      }
      model.addAttribute("sessionMessages", messages);
    
      return "sessionTest";
    }
    
    @PostMapping("/persistSession")
    public String persistMessage(@RequestParam("msg") String msg, HttpServletRequest request) {
      @SuppressWarnings("unchecked")
      List<String> messages = (List<String>) request.getSession().getAttribute("springSession");
      if (messages == null) {
        messages = new ArrayList<>();
        request.getSession().setAttribute("springSession", messages);
      }
      messages.add(msg);
      request.getSession().setAttribute("springSession", messages);
      return "redirect:/";
    }
    
    @PostMapping("/destroySession")
    public String destroySession(HttpServletRequest request) {
      request.getSession().invalidate();
      return "redirect:/";
    }

    sessionTest.html對應(yīng)頁面操作

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Spring Boot Session Example</title>
    </head>
    <body>
    <div>
        <form th:action="@{/persistSession}" method="post">
            <textarea name="msg" cols="40" rows="2"></textarea>
            <br> <input type="submit" value="保存" />
        </form>
    </div>
    <div>
        <h3>session列表</h3>
        <ul th:each="message : ${sessionMessages}">
            <li th:text="${message}">message</li>
        </ul>
    </div>
    
    <div>
        <form th:action="@{/destroySession}" method="post">
            <input type="submit" value="清空" />
        </form>
    </div>
    </body>
    </html>

    Spring中Session的作用是什么

    基于數(shù)據(jù)庫的Spring-Session

    1.引入maven依賴

    使用MySQL存儲,所以引入了MySQL。

    涉及到SpringBoot JDBC的配置,引入了Spring Boot JDBC Starter。

    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-core</artifactId>
      <version>2.5.0</version>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-jdbc</artifactId>
      <version>2.5.0</version>
    </dependency>
    
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.18</version>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    注意:

    No session repository could be auto-configured, check your configuration (session store type is 'jdbc')

    如果存在這個報錯,是因為沒有引入spring-boot-starter-jdbc,引入即可。

    2.配置application.properties文件

    主要包含兩部分,數(shù)據(jù)庫的配置以及Spring Session Jdbc配置。

    # 配置數(shù)據(jù)源相關(guān)內(nèi)容
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/spring_learn?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false
    spring.datasource.username=xxx
    spring.datasource.password=xxx
    spring.datasource.initialization-mode=always
    
    # session類型選擇jdbc
    spring.session.store-type=jdbc
    spring.session.jdbc.initialize-schema=always
    # 指定表名
    #spring.session.jdbc.table-name=SESSIONS
    # 超時時間
    spring.session.timeout=180s

    3.數(shù)據(jù)庫存儲解析

    默認(rèn)情況下,數(shù)據(jù)庫中會創(chuàng)建2張表。SPRING_SESSION和SPRING_SESSION_ATTRIBUTION。

    SPRING_SESSION用于存在session自身的一些屬性,如創(chuàng)建時間、過期時間等,詳細(xì)schema如下。

    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) DEFAULT NULL,
      PRIMARY KEY (`PRIMARY_ID`),
      UNIQUE KEY `SPRING_SESSION_IX1` (`SESSION_ID`),
      KEY `SPRING_SESSION_IX2` (`EXPIRY_TIME`),
      KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC

    SPRING_SESSION_ATTRIBUTION用于存儲session相關(guān)聯(lián)的屬性,schema如下。

    CREATE TABLE `SPRING_SESSION_ATTRIBUTES` (
      `SESSION_PRIMARY_ID` char(36) NOT NULL,
      `ATTRIBUTE_NAME` varchar(200) NOT NULL,
      `ATTRIBUTE_BYTES` blob NOT NULL,
      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
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC

    4.測試執(zhí)行

    SPRING_SESSION中的數(shù)據(jù)

    Spring中Session的作用是什么

    SPRING_SESSION_ATTRIBUTION中的數(shù)據(jù)。

    Spring中Session的作用是什么

    基于Redis的Spring-Session

    幾乎同樣的步驟

    maven依賴

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-data-redis</artifactId>
    </dependency>

    application.properties配置

    spring.session.store-type=redis
    spring.redis.host=127.0.0.1
    spring.redis.port=6379

    結(jié)果分析

    一次請求后,多了三個屬性,分析如下。

    key類型用途value
    spring:session:sessions:expires:${sessionId}string判斷sesssion是否存在
    spring:session:sessions:${sessionId}hashsession相關(guān)的屬性,包括有效期、創(chuàng)建時間、具體屬性等creationTime/lastAccessedTime/sessionAttr/maxInactiveInterval
    spring:session:expirations:1623656160000set存儲待過期的sessionId列表key: 過期的時間戳;value: 在這個時間戳將要過期的expire key列表。

    在訪問時,先通過第一個key,判斷session是否存在以及是否過期。如果沒有過期,可以通過第二個key獲取或者更新對應(yīng)的session詳情。

    對于第三個key,實際上Spring-Session-Redis會有特殊的用途,主要是為了Redis的keySpace-notificationhttps://redis.io/topics/notifications。核心目的是為了確保過期的session一定要觸發(fā)過期事件。關(guān)于這方面的解釋,可以看一下RedisIndexedSessionRepository中的注釋。

    訂閱Spring-Session的相關(guān)事件

    有些時候,我們比較關(guān)心Session的創(chuàng)建或者銷毀事件,做一些特殊的處理或者記錄?;赗edis的Spring-Session利用Spring Event將該事件發(fā)布出來,我們可以使用EventListener監(jiān)聽做處理。

    @Component
    @Slf4j
    public class AnnotationDrivenEventListener {
    
      @EventListener
      public void handleSessionCreated(SessionCreatedEvent sessionCreatedEvent) {
        String sessionId = sessionCreatedEvent.getSessionId();
        log.info("session id:{} created", sessionId);
      }
    
      @EventListener
      public void handleSessionDestroyed(SessionDestroyedEvent sessionDestroyedEvent) {
        String sessionId = sessionDestroyedEvent.getSessionId();
        log.info("session id:{} destroyed", sessionId);
      }
    }

    總結(jié)

    Spring Session提供了非常便利的,基于關(guān)系型數(shù)據(jù)庫或者Redis的Session解決方案。

    Redis版訪問速度快,基于Redis的過期策略,保證過期數(shù)據(jù)會被刪除,同時支持事件訂閱。

    數(shù)據(jù)庫版直接基于數(shù)據(jù)庫,無需單獨引入其他存儲。但是訪問速度相對較慢,過期數(shù)據(jù)需要依賴應(yīng)用程序自身進(jìn)行刪除。同時沒有提供事件訂閱能力。

    感謝各位的閱讀,以上就是“Spring中Session的作用是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Spring中Session的作用是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI