spring-boot-2.0.3不一樣系列之番外篇 - 自定義session管理,絕對有值得你看的地方

来源:https://www.cnblogs.com/youzhibing/archive/2018/09/21/9568178.html
-Advertisement-
Play Games

前言 還記得當初寫spring-session實現分散式集群session的共用的時候,裡面有說到利用filter和HttpServletRequestWrapper可以定製自己的getSession方法,實現對session的控制,從而將session存放到統一的位置進行存儲,達到session共 ...


前言

  還記得當初寫spring-session實現分散式集群session的共用的時候,裡面有說到利用filter和HttpServletRequestWrapper可以定製自己的getSession方法,實現對session的控制,從而將session存放到統一的位置進行存儲,達到session共用的目的。但是具體是如何實現的沒有提及,今天我們就從源碼的角度來看看shiro的session共用實現。

  路漫漫其修遠兮,吾將上下而求索!

  github:https://github.com/youzhibing

  碼雲(gitee):https://gitee.com/youzhibing

裝飾模式

  進入正題之前我們先來看看另外一個內容,放鬆下心情。儘管目前房價依舊很高,但還是阻止不了大家對新房的渴望和買房的熱情。如果大家買的是毛坯房,無疑還有一項艱巨的任務要面對,那就是裝修。對新房進行裝修並沒有改變房屋用於居住的本質,但它可以讓房子變得更漂亮、更溫馨、更實用、更能滿足居家的需求。在軟體設計中,我們也有一種類似新房裝修的技術可以對已有對象(新房)的功能進行擴展(裝修),以獲得更加符合用戶需求的對象,使得對象具有更加強大的功能。這種技術對應於一種被稱之為裝飾模式的設計模式。

  裝飾者模式又名包裝模式,以對客戶端透明的方式拓展對象的功能,能夠讓我們在不修改底層代碼的情況下,給我們的對象賦予新的職責。是繼承關係的一個替代方案。

  裝飾模式類圖

  裝飾模式中的角色:    

    抽象構件(Component)角色:給出一個抽象介面,以規範準備接收附加責任的對象。
    具體構件(ConcreteComponent)角色:定義一個將要接收附加責任的類。
    裝飾(Decorator)角色:持有一個構件(Component)對象的實例,並定義一個與抽象構件介面一致的介面。
    具體裝飾(ConcreteDecorator)角色:負責給構件對象“貼上”附加的責任

  源代碼實現

    Component.java

public interface Component {

    void sampleOperation();
}
View Code

    ConcreteComponent.java

public class ConcreteComponent implements Component {

    @Override
    public void sampleOperation() {
        // 寫具體業務代碼
        System.out.println("我是ConcreteComponent");
    }
}
View Code

    Decorator.java

public class Decorator implements Component {

    private Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void sampleOperation() {

        // 委派給具體的構建
        component.sampleOperation();
    }
}
View Code

    ConcreteDecorator.java

public class ConcreteDecorator extends Decorator{

    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void sampleOperation() {
        // 寫相關的業務代碼
        System.out.println("調用component方法之前業務處理");

        super.sampleOperation();

        // 寫相關的業務代碼
        System.out.println("調用component方法之後業務處理");
    }
}
View Code

    更多詳情在spring-boot-test下的com.lee.decorator包下

  jdk中的案例

    裝飾模式在Java語言中的最著名的應用莫過於Java I/O標準庫的設計了。由於Java I/O庫需要很多性能的各種組合,如果這些性能都是用繼承的方法實現的,那麼每一種組合都需要一個類,這樣就會造成大量性能重覆的類出現。而如果採用裝飾模式,那麼類的數目就會大大減少,性能的重覆也可以減至最少,因此裝飾模式是Java I/O庫的基本模式。

    由於Java I/O的對象眾多,這裡只畫出InputStream的一部分

    我們來捋一捋這個類圖在裝飾模式中角色的對應

      抽象構件(Component)角色:InputStream,這是一個抽象類,為各種子類型提供統一的介面
      具體構件(ConcreteComponent)角色:FileInputStream,實現了抽象構件角色所規定的介面
      裝飾(Decorator)角色:FilterInputStream,它實現了InputStream所規定的介面
      具體裝飾(ConcreteDecorator)角色:BufferedInputStream

自定義session管理

  我們先來看看一個請求的發起到響應的時序圖

  Interceptor依賴具體的框架(當然我們也可以自己實現),不是Servlet的內容,暫且先將其拋開,那麼相當於請求先經過Filter鏈,再到Servlet,然後servlet處理完之後,再經過Filter鏈返回給瀏覽器。

  此時我們要對session的獲取進行定製,我們能怎麼處理?兩種選擇,一是從Servlet入手,二是從Filter入手。那我們想一想,從Servlet入手可行嗎?可行,只是可行性非常低,因為我們需要定製的東西就太多了,容器的那套Servlet規範實現我們都需要自己來實現了。如果從Filter入手,我們可以繼續沿用容器的那套實現,並從中插入我們的定製內容,那麼改動的內容就很少了。具體如何實現,我們一起往下看

  定製session管理

    servlet容器的session創建

      在實現我們自己的session管理之前,我們先來看看session在servlet容器中的創建。

      客戶端第一次請求request.getSession()時,也就是說客戶端的請求中服務端第一次調用request.getSession()時,伺服器會創建了Session對象並保存在servlet容器的session集合中,同時生成一個Session id,並通過響應頭的Set-Cookie命令,向客戶端發送要求設置cookie的響應(cookie中設置Session id信息),客戶端收到響應後,在客戶端設置了一個JSESSIONID=XXXXXXX的cookie信息;接下來客戶端每次向伺服器發送請求時,請求頭都會帶上該cookie信息(包含Session id),那麼之後的每次請求都能從servlet容器的session集合中找到客戶端對應的session了,這樣也就相當於保持了用戶與伺服器的交互狀態。     

      註意:
        第一次請求request.getSession()時,請求頭沒帶session id的信息,響應頭中包括設置session id的cookie設置命令;之後客戶端的請求(不管服務端時候調用request.getSession()),請求頭都有session id信息,而響應頭再也不會有設置session id的cookie設置命令
        session以及session id是在第一次調用request.getSession()時創建的(session過期另說,不是本文內容)

        不同容器的session id名稱可能不一樣,JSESSIONID是tomcat中session id的預設名

    自定義session的創建與獲取

      不依賴任何框架,就用Filter + HttpServletRequestWrapper實現我們自己的簡單session管理。自定義Filter的作用是在請求到達Servlet之前,我們將HttpServletRequest封裝成我們自己的HttpServletRequestWrapper實現類:CustomizeSessionHttpServletRequest,那麼到達Servlet的HttpServletRequest對象實際上是CustomizeSessionHttpServletRequest;我們重寫CustomizeSessionHttpServletRequest的getSession方法,使其從我們自己的session容器中獲取,從而實現session的自定義管理。為了實現同一會話的效果,在創建session的時候,需要往response中添加cookie,保存session id,下次請求的時候,瀏覽器會將cookie信息傳過來,我們去cookie中獲取session id,根據session id取session容器獲取session,這樣就能保證同一會話效果了。

      具體代碼這裡就不貼了,大家去查看customize-session,效果如下

      先訪問http://localhost:8083/customize-session/test,此時是沒有產生session的,http://localhost:8083/customize-session/請求的是index.jsp,jsp請求了內置對象session,此時產生session,並讓瀏覽器設置緩存,那麼之後的每次請求都會帶上包含session id的緩存。

    關鍵部分類圖

      

      ServletRequestWrapper中有成員變數ServletRequest request;

    裝飾模式角色對應

      不是嚴格意義上的裝飾模式

      抽象構件(Component)角色:ServletRequest
      具體構件(ConcreteComponent)角色:無
      裝飾(Decorator)角色:ServletRequestWrapper
      具體裝飾(ConcreteDecorator)角色:CustomizeHttpServletRequest

總結

  1、裝飾模式

    文中裝飾模式講的不是很細,大家如果有什麼不懂的地方可以去我參考的兩本的兩本書中尋找更詳細的信息。

    jdk源碼中,I/O標準庫大量用到了裝飾模式和適配器模式,有興趣的小伙伴可以去詳細的看看。

  2、自定義session管理

    Filter攔截請求,將HttpServletRequest封裝成我們自己的CustomizeSessionHttpServletRequest,進而插入我們的session創建與獲取邏輯,因為session的獲取方式往往是:request.getSession();

    往response中添加cookie,需要在response提交之前,否則添加無效;

    另外我們自定義了HttpSession:CustomizeSession,目的是為了更好地控制session

  3、不足

    首先強調一點:方向與思路是沒錯的!

    目前只是實現了session的創建與獲取,實現的還比較一般,提升空間比較大;session管理還包括:session過期、session刷新等;另外session的存儲在本文中寫死了,沒有對外提交介面實現多方式存儲,好的方式應該是對外提供介面並提供預設實現。

  4、目的

    寫本文的目的只是讓大家對自定義session的管理有個簡單的認知,如果直接從shiro的session管理,或者spring-session的session管理入口,我們可能不知道如何去閱讀,畢竟這兩者是個成熟的體系,涉及的內容很多,我們可能會望而卻步了;但不管怎樣,實現方式都是一樣的,只是shiro、spring-session在此基礎上進行各種內容豐富,使得體系愈發成熟。

    為我的另外一篇博文做準備

參考

  《Head First 設計模式》

  《Java與模式》


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題目如下: 此題包含7小問: 先看此題的上半部分做了什麼,首先定義了一個叫Foo的函數,之後為Foo創建了一個叫getName的靜態屬性存儲了一個匿名函數,之後為Foo的原型對象新創建了一個叫getName的匿名函數。之後又通過函數變數表達式創建了一個getName的函數,最後再聲明一個叫getNa ...
  • function getIndex(ele){ var parent=ele.parentNode; var brothers=parent.children; for(var i=0,len=brothers.length;i<len;i++){ if(ele==brothers[i]){ ret ...
  • Http負載均衡 Nginx Nginx不僅是一個小巧且高效的HTTP伺服器,也可以做一個高效的負載均衡反向代理,通過它接受用戶的請求並分發到多個Mongrel進程可以極大提高Rails應用的併發能力 Tcp負載均衡 LVS LVS(LinuxVirtual Server)是由章文嵩博士主導開發的一 ...
  • 最近在看javascript高級程式設計這本書,看到了面向對象這一本部分,感覺很重要,所以再一次複習一遍,總結下知識,篇幅過多,分成了三部分,創建對象,原型和原型鏈,繼承,最好可以連著看,不懂得再跳回去看。 面向對象 (Object-Oriented,OO)的語言有一個標誌,那就是它們都有類的的概念 ...
  • 上一篇《HRMS(人力資源管理系統)-從單機應用到SaaS應用-系統介紹》我們已經詳細的分析了HRMS系統具備的功能,並且從HRMS系統的概念、系統功能、HR行業管理現狀及痛點、發展趨勢及行業前景、行業內的服務提供商情況、HRMS系統的建設意義及價值等方面進行了系統化的分析梳理。我想大家已經對於HR... ...
  • RESTful 介面是目前來說比較流行的一種介面,平常在開發中會非常常見。 有過和後端人員對接介面的小伙伴都應該知道,我們所做的大多數操作都是對資料庫的四格操作 “增刪改查” 對應到我們的介面操作分別是: 註意,這裡是我們約定,並非這些動作只能幹這件事情。從表層來說,除get外的其他方法,沒有什麼區 ...
  • 支付寶系統架構概況 典型處理預設 資金處理平臺 財務會計 支付清算 核算中心 交易 柔性事務 消息系統 數據分佈 數據緩存 支付寶技術產品線 支付寶的開源分散式消息中間件–Metamorphosis(MetaQ) Metamorphosis (MetaQ) 是一個高性能、高可用、可擴展的分散式消息中 ...
  • 讓你的項目有對象,你的項目如何才會有面向對象特征呢?沒有面向對象特征的項目不是好項目哦。此篇博文會使用到面向對象特征中的封裝繼承,還有就是枚舉類型。這篇博文教你如何讓你的項目體現面向對象特征。 最近公司需要做一個後臺系統,做了幾個月了老系統的維護更新,真心有點受不了,畢竟一個項目經過了幾個人的手,每 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...