ejb生命周期
对于经验丰富的专业人员来说,Java EE组件生命周期和与并发相关的详细信息可能不是新知识,但是对于初学者来说,这可能会花费一些时间。
就EJB而言,了解其生命周期 (以及相关的并发场景)对于确保使用EJB的正确用法和解决方案设计至关重要。 容易滥用它们!
我将在这篇文章中快速介绍无状态和有状态的 bean,暂时跳过Lima Beans!
- 有状态会话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();
}
}
观察结果
- 由于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生命周期