1. 程式人生 > >Tomcat 之session 持久化1

Tomcat 之session 持久化1

ajp 管理 dma element his upm 十月 amp exceptio

Tomcat 之session 持久化原理

幾個概念:

Manager 接口,其實就是指的是對 其Sesison 的管理, 其默認實現是StandardManager (內部沒有任何Store對象實例,而僅僅是通過 File 序列化實現的),它其實就是把session 保存到了本地的名為SESSIONS.ser 的文件;另外有PersistentManager,保存到本地文件(內部有一個FileStore)或數據庫表(通過JDBCStore)。 除此之外,還有提供 集群的BackupManager 等。

Store 則是專門指的是對Session 的存儲接口。

Store 有幾個實現, 一是基於本地文件的實現: FileStore, 另外一個是基於數據庫的實現: JDBCStore。 當然,這裏是沒有內存的實現的, 試想,基於的內存的話,又如何做持久化呢?

大致的原理:

Tomcat 是怎麽具體實行 session 持久的呢? 這樣的, 當我們訪問某個web 應用的時候,然後進行某些操作,這樣Session裏面會存在一些屬性,然後我們關閉tomcat,tomcat會把session 通過 Manager 寫到本地會數據庫中,然後我們啟動tomcat,tomcat會通過 Manger 恢復原先持久化的 Session相關屬性( 不管是StandardManager ,PersistentManager 都是這樣)。

註意,這裏我們必須要對某個web 應用做一些操作, 這樣, tomcat才會對應的分配一個 session, 否則session不存在, 自然, 也是無法持久化的; 另外 我們必須優雅的關閉tomcat, 這樣tomcat才會有機會在shutdown的時候 將session持久化。 通過 ctrl + c 或 shutdown腳本都是可以的, 但是 直接 kill, 是不行的。

Tomcat 的session 持久,默認是支持的, 好奇怪,竟然一直沒有發現! 那讓我們做個測試吧!

簡單測試:

這裏我做了個簡單的測試。怎麽測試呢?

思路:

就是通過LkServlet 對Session寫入一些東西, 然後停掉tomcat,再啟動tomcat,看tomcat 是否能夠把session恢復過來。

怎麽看它是否能夠恢復呢? 那就是 重啟後, 直接訪問SomeServlet, 通過SomeServlet 讀取 Session的 attribute, 讀取到了就是說明恢復成功,否則就是說明失敗。

寫session的 servlet:

package com.lk;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LkServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); if ("aa".equals(username) && "bb".equals(password)) { req.getRequestDispatcher("index.jsp").forward(req, resp); User user = new User(); user.setUsername(username); user.setPassword(password); req.getSession().setAttribute("user", user); // 這裏的user 必須實現Serializeable 接口, 否則無法恢復 req.getSession().setAttribute("aaa", "AAAAAA");// 普通 字符串屬性 req.getSession().setAttribute("bb", 111);  // 普通 數值屬性 req.getSession().setAttribute("ccc", "how are you ! 你好啊 ! "); } } }

測試用的 Servlet:

package com.lk;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SomeServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        doPost(req, resp);
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        
        HttpSession session = req.getSession();
        Enumeration<String> attributeNames = session.getAttributeNames();
        while (attributeNames.hasMoreElements()) {
            String string = (String) attributeNames.nextElement();
            System.out.println( string  + "               SomeServlet     "    +  session.getAttribute(string));
        }

        req.getRequestDispatcher("sess.jsp").forward(req, resp);
    }

}

其中:

package com.lk;

import java.io.Serializable;

public class User implements Serializable {


    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    
    
    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    private String username;
    private String password;

    
}

這裏的User 是必須實現Serializable 接口的, 否則呢, tomcat 是不能夠它持久到 本地文件或 數據庫中去的。 不過奇怪的是, 不實現雖然不能進行持久化,卻也不報錯, 這個讓我開始測試的時候, 迷惑了很久, 還以為是我哪裏配置的問題呢!!

但是 其他的一些基本屬性倒是 默認支持的。

web.xml 配置:

  <servlet>
      <servlet-name>aaa</servlet-name>
      <servlet-class>com.lk.LkServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>aaa</servlet-name>
      <url-pattern>/lk</url-pattern>
  </servlet-mapping>
  
    
  
  <servlet>
      <servlet-name>ss</servlet-name>
      <servlet-class>com.lk.SomeServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
      <servlet-name>ss</servlet-name>
      <url-pattern>/ss</url-pattern>
  </servlet-mapping>
  

重啟後立即訪問 http://localhost/ktb/ss , 結果:

十月 29, 2017 2:03:17 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-bio-80"]
十月 29, 2017 2:03:17 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["ajp-bio-8019"]
十月 29, 2017 2:03:17 下午 org.apache.catalina.startup.Catalina start
信息: Server startup in 2942 ms
aaa                     SomeServlet     AAAAAA
bb                      SomeServlet     111
ccc                     SomeServlet     how are you ! 你好啊 !
user                    SomeServlet     User [username=aa, password=bb]

可見恢復成功!

參考:

http://www.cnblogs.com/fx2008/p/4148389.html

Tomcat 之session 持久化1