在Web開發中,Session表示HTTP服務器與客戶端(例如瀏覽器)的“會話”,每個客戶端會有其對應的Session保存在服務器端,通常用來保存和客戶端關聯的一些信息,例如是否登錄、購物車等。
Session一般情況下是保存在服務器內存中。如果服務器重啟,Session就會丟失。另外,如果是集群環境,Web應用部署在多台服務器上,Session如果保存在各自的服務器上,就無法共享了。
針對這個問題,Jetty服務器提供了用於集群環境下的Session實現方式,即通過多台Jetty服務器連接到同一個Session數據庫來實現Session共享。
1、配置Session存儲到關系數據庫(MySQL為例):
配置jetty.xml:
打開Jetty目錄下的etc/jetty.xml,在Configure元素內部加入XML片段:
<Set name="sessionIdManager"> <New id="jdbcidmgr" class="org.eclipse.jetty.server.session.JDBCSessionIdManager"> <Arg> <Ref id="Server" /> </Arg> <Set name="workerName">fred</Set> <Call name="setDriverInfo"> <Arg>com.mysql.jdbc.Driver</Arg> <Arg>jdbc:mysql://192.168.20.1:3306/jetty_session?user=root&password=123</Arg> </Call> <Set name="scavengeInterval">60</Set> </New> </Set> <Call name="setAttribute"> <Arg>jdbcIdMgr</Arg> <Arg> <Ref id="jdbcidmgr" /> </Arg> </Call>
修改上面XML片段中的數據庫連接的URL,如果用其他關系數據庫,還要修改數據庫驅動。要注意在XML中&符號要轉義成&。
配置context xml:
在Jetty的webapps目錄下,新建一個XML文件,例如test.xml,這個XML用於配置一個web應用:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> <Set name="war">D:\test.war</Set> <Ref name="Server" id="Server"> <Call id="jdbcIdMgr" name="getAttribute"> <Arg>jdbcIdMgr</Arg> </Call> </Ref> <Set name="sessionHandler"> <New class="org.eclipse.jetty.server.session.SessionHandler"> <Arg> <New id="jdbcmgr" class="org.eclipse.jetty.server.session.JDBCSessionManager"> <Set name="sessionIdManager"> <Ref id="jdbcIdMgr" /> </Set> </New> </Arg> </New> </Set> </Configure>
其中,<Set name="war">D:\test.war</Set>配置web應用的war包,<Set name="contextPath">/test</Set>配置web應用的contextPath,例如http://localhost:8080/test。
啟動Jetty測試:
在啟動Jetty之前,還需要把MySQL驅動jar包放在Jetty的lib/ext目錄下。此外,還要創建好數據庫,准備好war包。
一切就緒以后,就可以啟動Jetty服務器測試Session是否已經保存在數據庫中。
通過java -jar start.jar命令啟動Jetty服務器,打開瀏覽器訪問頁面。可以看到在數據庫中會生成兩個表:jettysessionids、jettysessions,分別用於存儲session id和session的信息。如果重啟Jetty服務器,由於Session已經持久化到數據庫中,所以Session不會丟失。
需要注意的是,由於Session保存的是Java對象,會通過Java的序列化寫入數據庫,也就是Session中的對象必須支持序列化和反序列化,即實現Serializable接口。
配置文件說明:
如果看不懂上面兩段XML配置的話,這里做一個簡單的說明。
上面的這些XML實際上是Jetty的IOC配置文件,說到IOC首先會想到Spring框架,實際上Jetty的IOC和Spring的IOC解決的問題是類似的,只是XML的格式有些區別。
Jetty的IOC配置也很好理解,例如<Set name="contextPath">/test</Set>即調用setContextPath("/test"),<Call name="getAttribute"><Arg>jdbcIdMgr</Arg></Call>即調用getAttribute("jdbcIdMgr"),<New class="org.eclipse.jetty.server.session.SessionHandler"></New>即為Java實例化對象new SessionHandler()。
將上面的兩段XML“翻譯”成Java代碼:
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.session.JDBCSessionIdManager; import org.eclipse.jetty.server.session.JDBCSessionManager; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.webapp.WebAppContext; public class Main { public static void main(String[] args) throws Exception { Server server = new Server(8080); // 以下對應jetty.xml的配置 JDBCSessionIdManager sessionIdManager = new JDBCSessionIdManager(server); sessionIdManager.setWorkerName("fred"); sessionIdManager.setDriverInfo("com.mysql.jdbc.Driver", "jdbc:mysql://192.168.20.1:3306/jetty_session?user=root&password=123"); sessionIdManager.setScavengeInterval(60); server.setAttribute("jdbcIdMgr", sessionIdManager); // 以下對應context xml的配置 WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/test"); webapp.setWar("D:\\test.war"); JDBCSessionIdManager jdbcIdMgr = (JDBCSessionIdManager) server.getAttribute("jdbcIdMgr"); JDBCSessionManager sessionManager = new JDBCSessionManager(); sessionManager.setSessionIdManager(jdbcIdMgr); SessionHandler sessionHandler = new SessionHandler(sessionManager); webapp.setSessionHandler(sessionHandler); // 啟動服務器 server.setHandler(webapp); server.start(); server.join(); } }
運行Java代碼,同樣可以啟動服務器,將Session存入數據庫,實現同樣的效果。
2、配置Session存儲到MongoDB
配置jetty.xml:
打開etc/jetty.xml,在Configure元素內部加入XML片段:
<New id="mongodb" class="com.mongodb.MongoClient"> <Arg type="java.lang.String">192.168.20.1</Arg> <Arg type="int">27017</Arg> <Call name="getDB"> <Arg>jetty_session</Arg> <Call id="sessionDocument" name="getCollection"> <Arg>jetty_session_collection</Arg> </Call> </Call> </New> <Set name="sessionIdManager"> <New id="mongoIdMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager"> <Arg> <Ref id="Server" /> </Arg> <Arg> <Ref id="sessionDocument" /> </Arg> <Set name="workerName">fred</Set> <Set name="scavengePeriod">60</Set> </New> </Set> <Call name="setAttribute"> <Arg>mongoIdMgr</Arg> <Arg> <Ref id="mongoIdMgr" /> </Arg> </Call>
修改上面XML片段中的MongoDB的IP、端口號、數據庫名、Collection名。
配置context xml:
在Jetty的webapps目錄下,新建一個XML文件,例如test.xml,這個XML用於配置一個web應用:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd"> <Configure class="org.eclipse.jetty.webapp.WebAppContext"> <Set name="contextPath">/test</Set> <Set name="war">D:\test.war</Set> <Ref name="Server" id="Server"> <Call id="mongoIdMgr" name="getSessionIdManager"/> </Ref> <Set name="sessionHandler"> <New class="org.eclipse.jetty.server.session.SessionHandler"> <Arg> <New id="mongoMgr" class="org.eclipse.jetty.nosql.mongodb.MongoSessionManager"> <Set name="sessionIdManager"> <Ref id="mongoIdMgr"/> </Set> </New> </Arg> </New> </Set> </Configure>
啟動Jetty測試:
測試前,首先要吧兩個jar包放在Jetty的lib/ext目錄下,一個是MongoDB的驅動包,另一個是jetty-nosql的jar包,在http://repo1.maven.org/maven2/org/eclipse/jetty/jetty-nosql/下載對應版本的jar包。此外,在MongoDB中創建好對應的數據庫。
通過java -jar start.jar命令啟動Jetty服務器,打開瀏覽器打開頁面。可以看到在MongoDB中創建了配置的Collection並插入了數據:
“翻譯”成Java代碼:
將上面的兩段Jetty的IOC配置文件轉成Java代碼,直接運行可以實現同樣的功能:
import org.eclipse.jetty.nosql.mongodb.MongoSessionIdManager; import org.eclipse.jetty.nosql.mongodb.MongoSessionManager; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.webapp.WebAppContext; import com.mongodb.DB; import com.mongodb.DBCollection; import com.mongodb.MongoClient; public class Main { public static void main(String[] args) throws Exception { Server server = new Server(8080); // 以下對應jetty.xml的配置 MongoClient mongoClient = new MongoClient("192.168.20.1", 27017); DB db = mongoClient.getDB("jetty_session"); DBCollection collection = db.getCollection("jetty_session_collection"); MongoSessionIdManager sessionIdManager = new MongoSessionIdManager(server, collection); sessionIdManager.setWorkerName("fred"); sessionIdManager.setScavengePeriod(60); server.setAttribute("mongoIdMgr", sessionIdManager); // 以下對應context xml的配置 WebAppContext webapp = new WebAppContext(); webapp.setContextPath("/test"); webapp.setWar("D:\\test.war"); MongoSessionIdManager mongoIdMgr = (MongoSessionIdManager) server.getAttribute("mongoIdMgr"); MongoSessionManager sessionManager = new MongoSessionManager(); sessionManager.setSessionIdManager(mongoIdMgr); SessionHandler sessionHandler = new SessionHandler(sessionManager); webapp.setSessionHandler(sessionHandler); // 啟動服務器 server.setHandler(webapp); server.start(); server.join(); } }