有狀態會話Bean和無狀態會話Bean的區別狀態通常理解為對象的屬性,那麼無狀態就是沒有屬性,有狀態就是有屬性,這種理解是不正確的。這裡的無狀態確實與屬於相關,但有狀態會話Bean和無狀態會話Bean之間的區別並不是是否有屬性,而是是否儲存用戶端的屬性。有狀態會話Bean會儲存用戶端的狀態,而無狀態Bean不會專門儲存用戶端的狀態。這裡需要強調“專門”是因為無狀態會話Bean也會有成員變數,有成員變數就可以儲存狀態,但它不會專門為特定的用戶端儲存狀態。
區別的根本原因這與無狀態會話Bean和有狀態會話Bean的運行原理是相關的。對於有狀態會話Bean來說,只要有用戶端發送對有狀態會話Bean的訪問,伺服器都會建立一個會話Bean執行個體與該用戶端對應,這樣這個執行個體與這個用戶端就是一一對應的。如果用戶端在Bean執行個體中儲存了資訊,之後還可以使用。對於無狀態會話Bean來說,伺服器端會維持一個執行個體池,建立好若干個執行個體對象供用戶端調用。當從用戶端發送建立會話Bean的請求時,並不一定會真的建立EJB,多數情況下是從執行個體池中得到一個執行個體,用完之後重新放回執行個體池。如果下次再訪問,再從執行個體池中取出一個執行個體使用,並不一定是上次的執行個體。即使兩次訪問使用的是同一個執行個體,在兩次訪問之間也有可能有其他的用戶端訪問了該執行個體。所以,並不能保證在多次訪問之間的資訊會被儲存。所以,無狀態會話Bean不會專門儲存用戶端的資訊。
各自的優缺點因為有狀態會話Bean需要儲存特定用戶端的資訊,一個用戶端對應一個執行個體,既是在當時用戶端有串連沒有訪問的情況下,也要為這個用戶端保留這個執行個體。這樣隨著用戶端數量的增加,伺服器端需要建立的執行個體的數量也在增加,增加到一次程度對伺服器的效能就會有一定的影響。為了不對伺服器的效能產生影響,通常伺服器會進行一些最佳化。當用戶端的數量超過某個值之後,就不建立新的執行個體。雖然不建立新的執行個體,還是需要對使用者響應,這時候就採用共用執行個體的方式。會查看哪個執行個體雖然處於串連狀態,但是沒有訪問,然後把這個執行個體的狀態儲存起來,使用這個執行個體為新的請求服務,對於原來的用戶端來說,稱為掛起。如果原來的用戶端又發送請求了,會重新尋找一個閒置執行個體並且把已經儲存好的狀態恢複回來,這個過程稱為啟用。所以在有狀態會話Bean的訪問過程,經常會發生尋找執行個體,啟用掛起等操作,所以效率比較低。而發送對無狀態會話Bean的請求的時候,可以隨便取一個閒置執行個體為用戶端服務,所以效率比較高。有狀態會話Bean的好處是,可以儲存用戶端的狀態,所以用戶端在後續訪問的時候就可以少傳遞一些參數。而狀態會話Bean需要傳遞方法執行過程中需要的所有參數。
如何選擇根據上面分析的有狀態會話Bean和無狀態會話Bean的優缺點。如果要頻繁的訪問,並且多次訪問之間會共用一些資訊,這時候應該使用有狀態會話Bean。對於不經常使用的功能,可以使用無狀態會話Bean。無狀態會話Bean的使用要比有狀態會話Bean的使用多。
一個描述無狀態會話Bean和有狀態會話Bean區別的執行個體下面的代碼是一個表示購物車的有狀態會話Bean:package ch19; import javax.ejb.Stateful;import java.util.List; @Statefulpublic class CartBean implements Cart{ private String customerId; private String customerName; private ArrayList<String> contents; public void initialize(String person) throws BookException { if (person == null) { throw new BookException("不允許沒有使用者!"); } else { customerName = person; } customerId = "0"; contents = new ArrayList<String>(); } public void initialize(String person, String id) throws BookException { if (person == null) { throw new BookException("不允許沒有使用者!"); } else { customerName = person; } IdVerifier idChecker = new IdVerifier(); if (idChecker.validate(id)) { customerId = id; } else { throw new BookException("無效的ID: " + id); } contents = new ArrayList<String>(); } public void addBook(String title) { contents.add(title); } public void removeBook(String title) throws BookException { boolean result = contents.remove(title); if (result == false) { throw new BookException(title + " 不在購物車中。"); } } public List<String> getContents() { return contents; } @Remove() public void remove() { contents = null; }}假設業務介面是Cart代碼來源:《Java EE 5實用教程——基於WebLogic和Eclipse》 如果在用戶端注入兩個EJB對象,通過執行個體注入,代碼如下:@EJBCart cart1;@EJBCart cart2;調用業務方法的代碼如下:cart1.initialize(“張三”);cart1.addBook(“JSP2.0基礎教程”);cart1.addBook(“Java EE5實用教程”);cart2.initialize(“李四”);cart2.addBook(“ASP網站開發”);cart2.addBook(“最新C#執行個體開發”);List<String> books=cart1.getContents();out.println(“cart1中的圖書為:”);for(int i=0;i<books.size();i++){ out.println(books.get(i));}books=cart2.getContents();out.println(“<br>cart2中的圖書為:”);for(int i=0;i<books.size();i++){ out.println(books.get(i));}執行的結果如下:cart1中的圖書為:JSP2.0基礎教程 Java EE5實用教程cart2中的圖書為:ASP網站開發 最新C#執行個體開發 如果把CartBean中的Stateful改成Stateless,重新運行會得到下面的執行結果:cart1中的圖書為:ASP網站開發 最新C#執行個體開發cart2中的圖書為:ASP網站開發 最新C#執行個體開發 為什麼兩次的結果不相同呢?有狀態會話Bean的使用cart1和cart2對應兩個Bean執行個體,各自有各自的屬性。而在無狀態會話Bean中,cart1和cart2實際上對應的是同一個Bean執行個體,所以通過cart1添加的圖書被cart2的添加操作給覆蓋了,所以最後cart1得到的圖書不再是存放進去的“Java Web程式設計基礎教程”和“Java EE 5實用教程”。通過這個執行個體可以更好的理解又狀態會話Bean和無狀體會話Bean的區別。