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 –小心消费!

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() {
    }

    @Inject
    MySingletonBean mySingleton;

    @Override
    protected 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个并发线程(是的,只有两个。这更多是演示,而不是负载测试竞赛!)

cmc-jmeter-1

cmc-jmeter-2

cmc结果

观察结果

查看日志,可以轻松得出以下几点:

  • 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)上使用同步来完成。

建议阅读

干杯!

翻译自: https://www.javacodegeeks.com/2014/09/ejb-3-x-lifecycle-and-concurrency-models-part-2.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值