EJB 3.x:生命周期和并发模型(第1部分)

Java EE组件生命周期和与并发相关的详细信息对于经验丰富的专业人员而言可能不是新知识,但是对于初学者而言,这可能需要花费一些时间。



并发

就EJB而言,了解其生命周期 (以及相关的并发场景)对于确保使用EJB的正确用法和解决方案设计至关重要。 容易滥用它们!

豆的生命周期

豆的生命周期

我将在这篇文章中快速介绍 状态豆和有状态豆,暂时跳过Lima Beans!

  • 有状态会话Bean –生命周期+并发处理
  • 无状态 bean –仅用于并发模型,因为我在之前的一篇文章中简要介绍了生命周期。

有状态会话Bean的生命周期中有哪些不同的状态?

  • 不存在
  • 准备
  • 钝化的

是什么触发了他们?

这是一个快速的表格快照和一个高级图表。 有关更多详细信息,请继续阅读。 。 。

无状态会话Bean生命周期状态图

无状态会话Bean生命周期状态图

注意 :DNE –不存在, R –就绪, P –钝化,SFSB –有状态会话Bean

国家过渡 扳机 回呼
DNE转R 首次通过JNDI或DI访问SFSB实例时 @PostConstruct
R到DNE 容器关闭,客户端调用用@Remove注释的方法,Bean达到由DD或@StatefulTimeout指定的空闲超时阈值 @PreDestroy
R到P EJB容器会钝化闲置的bean,并根据特定算法将其从活动内存中删除 @PrePassivate
P到DNE Bean达到由DD或@StatefulTimeout指定的空闲超时阈值 注意 :不会调用@PreDestroy注释方法
从P到R 客户端被钝化但尚未超时后调用SFSB实例时 @PostActivate


注意 :如果SFSB在请求处理期间引发异常,则其实例将被破坏,即进入DNE状态。 在这种情况下,不会调用@PreDestroy注释方法

现在,我们对SFSB的生命周期有了一些了解,让我们尝试看一下这些Bean在负载下的行为,即当多个用户一次使用该应用程序时,它转化为并发访问SFSB实例。

有状态会话Bean:并发管理

线程安全是EJB的核心功能之一。 需要注意的一点是,此线程安全性是免费的,并且不需要任何与并发相关的构造由Bean开发人员自己进行编码 (有一些例外 )。 就SFSB而言,EJB容器确保在特定时间只有一个线程可以访问bean实例。

在此示例中,我们尝试通过JMeter调用测试Servlet来模拟对SFSB单个实例的并发访问 。 Servlet通过DI注入bean并在其上调用方法。 SFSB方法仅使用Thread.sleep()假装好像正在执行某些操作。

package com.abhirockzz.wordpress.ejb.lifecycle.stateful;

import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateful;

@Stateful
public class MyStatefulBean {

    public MyStatefulBean() {
    }

    public void act() {
        System.out.println("Entered MyStatefulBean/act() on " + new Date().toString() + " . SFSB 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 MyStatefulBean/act() on " + new Date().toString() + " . SFSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());

    }
}
package com.abhirockzz.wordpress.ejb.lifecycle.stateful;

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 = "SFSBTestServlet", urlPatterns = {"/SFSBTestServlet"})
public class SFSBTestServlet extends HttpServlet {

    public SFSBTestServlet() {
    }

    @Inject
    MyStatefulBean mySFSB;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("Entered SFSBTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());
        mySFSB.act();
    }

}


通过JMeter的HTTP GET请求

通过JMeter的HTTP GET请求

通过JMeter进行并发请求模拟

通过JMeter进行并发请求模拟

观察结果
  • 由于Servlet本身不是线程安全的,因此实际上有多个线程将进入doGet()方法
  • 并发访问SFSB的单个实例(通过hashCode结果证明)(请参阅记录的语句中的线程名称)
  • 但是,只有一个线程将能够访问SFSB实例–当SFSB方法返回时,其他线程等待其轮换。 通过控制台上的日志语句可以明显看到此延迟
控制台日志

控制台日志

无状态豆呢?

这些bean 本质上是线程安全的为什么呢 这是因为默认情况下,容器确保每个新请求都由 Bean 的新实例提供服务。 请记住,客户端可以通过3种可能的方式获得对无状态bean的引用-DI,JNDI或通过远程接口(RMI)。 在所有这些情况下,都是容器(代理)拦截了该调用–因此,即使看似多个线程正在访问同一bean实例,它实际上也不是同一实例!

package com.abhirockzz.wordpress.ejb.lifecycle.stateless;

import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.Stateless;

@Stateless
public class MyStatelesslBean {

    public void act() {

        System.out.println("Entered MyStatelesslBean/act() on " + new Date().toString() + " . SLSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(MyStatelesslBean.class.getName()).log(Level.SEVERE, null, ex);
        }

        System.out.println("Exit MyStatelesslBean/act() on " + new Date().toString() + " . SLSB instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());
    }
}
package com.abhirockzz.wordpress.ejb.lifecycle.stateless;

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 = "SLSBTestServlet", urlPatterns = {"/SLSBTestServlet"})
public class SLSBTestServlet extends HttpServlet {

    @Inject
    MyStatelesslBean slsb;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        System.out.println("Entered SLSBTestServlet/doGet() on " + new Date().toString() + " . Servlet instance " + this.hashCode() + " Thread : " + Thread.currentThread().getName());

        slsb.act();

    }

}

观察结果
  • 由于Servlet本身不是线程安全的,因此实际上有多个线程将进入doGet()方法
  • 容器正在选择SLSB的不同实例 (通过hashCode结果显而易见)来管理并发请求(请参见记录的语句中的线程名称)。
  • 尽管有并发请求,但每个请求线程都由一个新实例提供服务
控制台日志

控制台日志

目前为止就这样了! 我计划在以后的文章中介绍Singleton Session bean。 敬请关注 。 。 。 。

谢谢阅读!

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值