EJB 3.x:生命周期和并发模型(第2部分)
這是兩部分系列的第二篇。 第一部分介紹了有狀態和無狀態EJB的生命周期以及并發行為。 在這篇文章中,我將介紹Singleton EJB 。
Singleton模式可以說是最常用(有時被濫用!)的模式。
單噸又愛它!
Java EE使我們無需編寫顯式代碼(如上圖所示)即可實現Singleton模式。
EJB 3.1本身就是Java EE 6的一部分,因此引入了Singleton EJB。
所需要的只是在一個豆類上提供一個@ javax.ejb.Singleton (類級別)注釋(如果需要完善其他方面,還可以添加更多注釋),以將其指定為Singleton會話bean。
JVM中只有一個實例和一個Singleton EJB實例 –無論有多少客戶端訪問它。 它不像有狀態SB(一個在整個生命周期內附加到單個客戶端的bean實例),也不像無狀態SB(每個狀態),每個客戶端請求都有一個新實例。
Singleton Session Bean的生命周期中有哪些不同的狀態?
Singleton Bean的生命周期與無狀態會話Bean相同-實際上,這是此Bean類型的簡單方面之一:
- 不存在
- 準備
狀態如何變化? 是什么觸發了他們?
這是一個快速的表格快照和一個高級圖表。 。 。
單例豆–狀態轉換
| DNE轉R | 首次通過JNDI / DI訪問實例或由容器使用@Startup或@DependsOn自動實例化實例時 | @PostConstruct |
| R到DNE | 容器關閉–銷毀bean實例,或者@PostConstruct注釋方法中發生異常 | @PreDestroy |
注意 :DNE –不存在, R –就緒
如前所述,生命周期是Singleton bean的較簡單功能之一。 了解它們的并發方面至關重要。
Singleton Session Bean:并發管理
如前所述– Singleton在JVM中只有一個實例。 在Java EE環境中,并發訪問是不可避免的–這就是為什么我們首先使用Java EE之類的技術的原因! 需要確保根據用例和需求,仔細考慮Singleton bean的并發( 鎖定 )策略。
Singleton –小心消費!
Singleton bean并發可以分為2個主要類別 :
- 容器托管(默認)
- Bean托管
容器管理并發
- 顧名思義,容器為Bean應用了明智的默認配置
- 可以使用注釋和XML(部署描述符)進行控制
- 在bean類本身上使用@ javax.ejb.ConcurrencyManagement注釋明確聲明
- 默認值為javax.ejb.ConcurrencyManagementType.CONTAINER
- 容器提供了兩種可能的鎖定策略 –適用于bean類或其單個方法
- @ javax.ejb.Lock ,值為javax.ejb.LockType.READ-允許在沒有寫鎖的情況下進行并發訪問
- 可以在Bean類或方法上指定@ javax.ejb.AccessTimeout,以確保線程在不確定的時間段內不會阻塞或持有鎖
Bean托管并發
- 該名稱清楚地表明– Bean的并發方面留給開發人員。 與容器通過上述構造提供的并發控制相比,需要更好的并發控制是有意義的
- 需要使用適當的Java并發構造,例如同步,易失等
- 很難正確!
代碼示例
讓我們看一個簡單的代碼片段,以便更好地理解上述事實:
方案一 –容器管理的并發(默認,未明確指定鎖定類型)
package com.abhirockzz.wordpress.ejb.lifecycle.singleton;import com.abhirockzz.wordpress.ejb.lifecycle.stateful.MyStatefulBean; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.Singleton; import javax.ejb.Startup;@Singleton @Startup public class MySingletonBean {public void act() {System.out.println("Entered MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());try {Thread.sleep(2000);} catch (InterruptedException ex) {Logger.getLogger(MyStatefulBean.class.getName()).log(Level.SEVERE, null, ex);}System.out.println("Exit MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());} }package com.abhirockzz.wordpress.ejb.lifecycle.singleton;import java.io.IOException; import java.util.Date; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;@WebServlet(name = "SingletonTestServlet", urlPatterns = {"/SingletonTestServlet"}) public class SingletonTestServlet extends HttpServlet {public SingletonTestServlet() {}@InjectMySingletonBean mySingleton;@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {System.out.println("Entered SingletonTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());mySingleton.act();}}使用Apache JMeter –我在SingletonTestServlet觸發了2個并發線程(是的,只有兩個。這更多是演示,而不是負載測試競賽!)
觀察結果
查看日志,可以輕松得出以下幾點:
- Servlet當然不是線程安全的,因此兩個線程同時進入
- 其中一個線程在Singleton bean類中輸入方法(標記為紅色),并且由于容器強制使用默認的WRITE鎖定類型 ,因此禁止進一步訪問
- 第一個線程完成執行后,最初被阻塞的第二個線程(標記為綠色)就有機會執行Singleton bean方法
- 很簡單!
方案二 –堅持容器管理的并發性。 將顯式鎖定類型從WRITE更改為READ
import com.abhirockzz.wordpress.ejb.lifecycle.stateful.MyStatefulBean; import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; import javax.ejb.ConcurrencyManagement; import javax.ejb.ConcurrencyManagementType; import javax.ejb.Lock; import javax.ejb.LockType; import javax.ejb.Singleton; import javax.ejb.Startup;@Singleton @Startup @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) public class MySingletonBean {@Lock(LockType.READ)public void act() {System.out.println("Entered MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());try {Thread.sleep(2000);} catch (InterruptedException ex) {Logger.getLogger(MyStatefulBean.class.getName()).log(Level.SEVERE, null, ex);}System.out.println("Exit MySingletonBean/act() on " + new Date().toString() + " . Singleton instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());} }當應用程序被2個并發線程轟炸(雙關!)時,會發生什么情況。 。 。 ?
- 如預期的那樣,兩個線程同時進入Servlet
- 線程之一進入Singleton bean類中的方法(標記為紅色)
- 第二個線程(標記為綠色)也設法同時進入Singleton bean方法(檢查時間戳記)
- 再次-非常簡單!
我現在所描述的不是Bean管理并發。 如上所述,將BMC用于Singleton會將責任轉移給開發人員,并且他可以自由地將并發功能編碼到Bean中,這可以簡單地在每種方法或其他機制(例如,從java.util.concurrent API)上使用同步來完成。
建議閱讀
- EJB(3.2)規范
干杯!
翻譯自: https://www.javacodegeeks.com/2014/09/ejb-3-x-lifecycle-and-concurrency-models-part-2.html
總結
以上是生活随笔為你收集整理的EJB 3.x:生命周期和并发模型(第2部分)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Gradle构建和应用AST转换
- 下一篇: 简而言之,JUnit:另一个JUnit教