Spring-Session實現(xiàn)Session共享入門教程

任何一種技術(shù)的出現(xiàn),都是來解決特定的問題的!

本篇開始學習Spring-Session相關(guān)的一些知識學習整理,讓我們開始吧!

Spring-Session介紹

  1. Spring-Session使用的場景隘冲?

HttpSession是通過Servlet容器進行創(chuàng)建和管理的,在單機環(huán)境中绑雄。通過Http請求創(chuàng)建的Session信息是存儲在Web服務(wù)器內(nèi)存中展辞,如Tomcat/Jetty。

假如當用戶通過瀏覽器訪問應(yīng)用服務(wù)器万牺,session信息中保存了用戶的登錄信息罗珍,并且session信息沒有過期失,效那么用戶就一直處于登錄狀態(tài)脚粟,可以做一些登錄狀態(tài)的業(yè)務(wù)操作覆旱!


單機session

但是現(xiàn)在很多的服務(wù)器都采用分布式集群的方式進行部署,一個Web應(yīng)用核无,可能部署在幾臺不同的服務(wù)器上扣唱,通過LVS或者Nginx等進行負載均衡(一般使用Nginx+Tomcat實現(xiàn)負載均衡)。此時來自同一用戶的Http請求將有可能被分發(fā)到不同的web站點中去(如:第一次分配到A站點团南,第二次可能分配到B站點)噪沙。那么問題就來了,如何保證不同的web站點能夠共享同一份session數(shù)據(jù)呢吐根?

假如用戶在發(fā)起第一次請求時候訪問了A站點正歼,并在A站點的session中保存了登錄信息,當用戶第二次發(fā)起請求拷橘,通過負載均衡請求分配到B站點了局义,那么此時B站點能否獲取用戶保存的登錄的信息呢?答案是不能的冗疮,因為上面說明萄唇,Session是存儲在對應(yīng)Web服務(wù)器的內(nèi)存的,不能進行共享赌厅,此時Spring-session就出現(xiàn)了穷绵,來幫我們解決這個session共享的問題轿塔!

集群session
  1. 如何進行Session共享呢特愿?

簡單點說就是請求http請求經(jīng)過Filter職責鏈仲墨,根據(jù)配置信息過濾器將創(chuàng)建session的權(quán)利由tomcat交給了Spring-session中的SessionRepository,通過Spring-session創(chuàng)建會話揍障,并保存到對應(yīng)的地方目养。

session共享

實際上實現(xiàn)Session共享的方案很多,其中一種常用的就是使用Tomcat毒嫡、Jetty等服務(wù)器提供的Session共享功能癌蚁,將Session的內(nèi)容統(tǒng)一存儲在一個數(shù)據(jù)庫(如MySQL)或緩存(如Redis,Mongo)中兜畸,

而上面說的使用Nginx也可以努释,使用ip_hash策略。
【Nginx】實現(xiàn)負載均衡的幾種方式
在使用Nginx的ip_hash策略時候咬摇,每個請求按訪問ip的hash結(jié)果分配伐蒂,這樣每個訪客固定訪問一個后端服務(wù)器,也可以解決session的問題肛鹏。

  1. Spring官方介紹
    Why Spring Session & HttpSession?

Spring會話提供了與HttpSession的透明集成,允許以應(yīng)用程序容器(即Tomcat)中性的方式替換HttpSession逸邦,但是我們從中得到了什么好處呢?

  • 集群會話——Spring會話使支持集群會話變得微不足道,而不需要綁定到應(yīng)用程序容器的特定解決方案在扰。

  • 多個瀏覽器會話——Spring會話支持在單個瀏覽器實例中管理多個用戶會話(也就是多個經(jīng)過驗證的帳戶缕减,類似于谷歌)。

  • RESTful api——Spring會話允許在header中提供會話id以使用RESTful api芒珠。

  • Spring Session & WebSockets的完美集成桥狡。

項目搭建

整個項目的整體骨架:

項目的整體骨架

基于XML配置方式的Spring Session

本次只講解xml配置方式,javaConfig配置可以參考官方文檔:Spring Java Configuration

環(huán)境說明

本次項目需要用戶Nginx和Redis妓局,如果沒有配置Nginx的請看這里: Windows上Nginx的安裝教程詳解

沒有配置Redis的請看這里:Redis——windows環(huán)境安裝Redis和Redis sentinel部署教程

配置好了上面的環(huán)境总放,后下面開始正式的Spring-session搭建過程了!

1.添加項目依賴

首先新建一個Maven的Web項目好爬,新建好之后在pom文件中添加下面的依賴:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.spring</groupId>
    <artifactId>learn-spring-session</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>First Learn Spring Session</name>

    <properties>
      <jdk.version>1.7</jdk.version>
      <spring.version>4.3.4.RELEASE</spring.version>
      <spring-session.version>1.3.1.RELEASE</spring-session.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api  -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>${spring-session.version}</version>
            <type>pom</type>
        </dependency>
        
       <dependency>
            <groupId>biz.paluch.redis</groupId>
            <artifactId>lettuce</artifactId>
            <version>3.5.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>


    </dependencies>

   

</project>


2.web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:spring/*xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <!--DelegatingFilterProxy將查找一個Bean的名字springSessionRepositoryFilter丟給一個過濾器局雄。為每個請求
  調(diào)用DelegatingFilterProxy, springSessionRepositoryFilter將被調(diào)用-->
  <filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  </filter>


  <filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>


  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

</web-app>
        
        

3.Xml的配置

在resources 下面新建一個xml,名詞為 application-session.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

    <context:annotation-config/>


    <!--創(chuàng)建一個Spring Bean的名稱springSessionRepositoryFilter實現(xiàn)過濾器存炮。
    篩選器負責將HttpSession實現(xiàn)替換為Spring會話支持炬搭。在這個實例中,Spring會話得到了Redis的支持穆桂。-->
    <bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
    <!--創(chuàng)建了一個RedisConnectionFactory宫盔,它將Spring會話連接到Redis服務(wù)器。我們配置連接到默認端口(6379)上的本地主機享完!-->
    <bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>

</beans>

4.測試代碼

新建 LoginServlet.java

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {


        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;


        request.getSession().setAttribute("testKey", "742981086@qq.com");

        request.getSession().setMaxInactiveInterval(10*1000);

        response.sendRedirect(request.getContextPath() + "/session");

    }

}

新建 SessionServlet.java

@WebServlet("/session")
public class SessionServlet extends HttpServlet {

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        System.out.println(request.getRemoteAddr());
        System.out.print(request.getRemoteHost() + " : " + request.getRemotePort());

        String sesssionID = request.getSession().getId();
        System.out.println("-----------tomcat2---sesssionID-------" + sesssionID);

        String testKey = (String)request.getSession().getAttribute("testKey");
        System.out.println("-----------tomcat2-testKey-------" + testKey);

        PrintWriter out = null;
        try {
            out = response.getWriter();
            out.append("tomcat2 ---- sesssionID : " + sesssionID);
            out.append("{\"name\":\"dufy2\"}" + "\n");
            out.append("tomcat2 ----- testKey : " + testKey + "\n");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(out != null){
                out.close();
            }
        }

    }

}

效果演示

1.啟動Redis灼芭,默認端口6379就行!

2.配置Nginx般又,啟動Nginx

Nginx的配置彼绷,輪詢方式:

#user nobody;
worker_processes 1;
events{
    worker_connections 1024;
    }
http{
    upstream myproject {
        server 127.0.0.1:8888;
        server 127.0.0.1:9999;

    }
    server {
        listen 8080;
        server_name localhost;

        location / {
            proxy_pass http://myproject;
            }
        }
}

3.啟動Tomcat1和Tomcat2

將上面搭建好的項目放入兩個Tomcat中巍佑,分別啟動。使用Nginx負載均衡均驗證Session是否共享成功寄悯!

tomcat1 : http://localhost:8888/
tomcat2 : http://localhost:9999/

訪問 http://localhost:8080/ 可以看到萤衰,每次刷新頁面,請求都分發(fā)到不同的Tomcat里面猜旬,如圖

通過Nginx負載到tomcat1

然后使用 http://localhost:8080/login 看到地址欄重定向到/session .發(fā)現(xiàn)瀏覽器返回了數(shù)據(jù)脆栋,進入tomcat2中,然后再次刷新請求進入了tomcat1洒擦,發(fā)現(xiàn)tomcat2中和tomcat1 sessionId一樣椿争,并且在tomcat1中存的testKey,在Tomcat2中也可以獲取熟嫩,不僅SessionId可以共享丘薛,其他一些數(shù)據(jù)也可以進行共享!

通過Nginx負載到tomcat2

如何在Redis中查看Session數(shù)據(jù),可以使用命令邦危,或者在Windows的RedisDesktopManager中查看洋侨!

Redis中查看Session信息

key的簡單介紹說明:


# 存儲 Session 數(shù)據(jù),數(shù)據(jù)類型hash
Key:spring:session:sessions:XXXXXXX

# Redis TTL觸發(fā)Session 過期。(Redis 本身功能)倦蚪,數(shù)據(jù)類型:String
Key:spring:session:sessions:expires:XXXXX

#執(zhí)行 TTL key 希坚,查看剩余生存時間


#定時Job程序觸發(fā)Session 過期。(spring-session 功能)陵且,數(shù)據(jù)類型:Set
Key:spring:session:expirations:XXXXX


驗證成功裁僧!

總結(jié)

Spring-Session在實際的項目中使用還是比較廣泛的,本次搭建采用最簡單的配置慕购,基本都是采用官方文檔中默認的方式聊疲,因為是入門的教程就沒有寫的很復(fù)雜,后面慢慢深入沪悲!期待后續(xù)的教程吧获洲!

參考文章

使用Spring Session和Redis解決分布式Session跨域共享問題57406162

學習Spring-Session+Redis實現(xiàn)session共享

利用spring session解決共享Session問題


本系列教程

【入門】分布式Session一致性入門簡介

【第一篇】Spring-Session實現(xiàn)Session共享入門教程

【第二篇】Spring-Session實現(xiàn)Session共享Redis集群方式配置教程

【第三篇】Spring-Session實現(xiàn)Session共享實現(xiàn)原理以及源碼解析


如果您覺得這篇博文對你有幫助,請點下面的喜歡殿如,讓更多的人看到贡珊,謝謝!

如果帥氣(美麗)涉馁、睿智(聰穎)门岔,和我一樣簡單善良的你看到本篇博文中存在問題,請指出烤送,我虛心接受你讓我成長的批評寒随,謝謝閱讀!
祝你今天開心愉快!


歡迎訪問我的csdn博客妻往,我們一同成長逢防!

不管做什么,只要堅持下去就會看到不一樣蒲讯!在路上,不卑不亢!

博客首頁http://blog.csdn.net/u010648555

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灰署,一起剝皮案震驚了整個濱河市判帮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溉箕,老刑警劉巖晦墙,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肴茄,居然都是意外死亡晌畅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門寡痰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抗楔,“玉大人,你說我怎么就攤上這事拦坠×铮” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵贞滨,是天一觀的道長入热。 經(jīng)常有香客問我,道長晓铆,這世上最難降的妖魔是什么勺良? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮骄噪,結(jié)果婚禮上尚困,老公的妹妹穿的比我還像新娘。我一直安慰自己链蕊,他們只是感情好尾组,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著示弓,像睡著了一般讳侨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奏属,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天跨跨,我揣著相機與錄音,去河邊找鬼。 笑死勇婴,一個胖子當著我的面吹牛忱嘹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耕渴,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拘悦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了橱脸?” 一聲冷哼從身側(cè)響起础米,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎添诉,沒想到半個月后屁桑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡栏赴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年蘑斧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片须眷。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡竖瘾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出花颗,到底是詐尸還是另有隱情准浴,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布捎稚,位于F島的核電站乐横,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏今野。R本人自食惡果不足惜葡公,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望条霜。 院中可真熱鬧催什,春花似錦、人聲如沸宰睡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拆内。三九已至旋圆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間麸恍,已是汗流浹背灵巧。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工搀矫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刻肄。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓瓤球,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敏弃。 傳聞我的和親對象是個殘疾皇子卦羡,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容