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

ejb生命周期

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



并发

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

豆的生命周期

豆的生命周期

我将在这篇文章中快速介绍无状态有状态的 bean,暂时跳过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

ejb生命周期

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值