Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jakarta ee JSF请求范围bean会在每个请求上不断重新创建新的有状态会话bean吗?_Jakarta Ee_Jsf 2_Ejb 3.0 - Fatal编程技术网

Jakarta ee JSF请求范围bean会在每个请求上不断重新创建新的有状态会话bean吗?

Jakarta ee JSF请求范围bean会在每个请求上不断重新创建新的有状态会话bean吗?,jakarta-ee,jsf-2,ejb-3.0,Jakarta Ee,Jsf 2,Ejb 3.0,我正在使用JSF、PrimeFaces、Glassfish和Netbeans构建我的第一个JavaEE应用程序。因为我是新来的,有可能我在处理核心问题时出错了 核心问题:我想安全地维护用户的信息。关于是否应该在JSF会话bean或有状态会话EJB中维护它,似乎存在着相互矛盾的观点。我尝试使用有状态会话EJB,因为这样更安全 问题是,我的应用程序似乎正在创建该bean的多个实例,而我希望它创建一个实例并重新使用它。如果我刷新页面,它将运行@PostConstruct和@postactive三次,所

我正在使用JSF、PrimeFaces、Glassfish和Netbeans构建我的第一个JavaEE应用程序。因为我是新来的,有可能我在处理核心问题时出错了

核心问题:我想安全地维护用户的信息。关于是否应该在JSF会话bean或有状态会话EJB中维护它,似乎存在着相互矛盾的观点。我尝试使用有状态会话EJB,因为这样更安全

问题是,我的应用程序似乎正在创建该bean的多个实例,而我希望它创建一个实例并重新使用它。如果我刷新页面,它将运行
@PostConstruct
@postactive
三次,所有这些都使用不同的实例。然后,当我重新部署应用程序时,它们都会被销毁

我是否误解了它应该如何工作,或者是配置错误

我将尝试显示一个精简的代码示例:

basic.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        Hello from Facelets
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
        <c:if test="#{loginController.authenticated}">
            Authenticated
        </c:if>
    </h:body>
</html>
UserBean
(不包括
UserBeanLocal
接口)

最后,这里是刷新三次后的Glassfish输出:

INFO:#####创建用户Bean:boundary._UserBean_Serializable@2e644784
信息:认证测试自动通过。
信息:认证测试自动通过。
信息:认证测试自动通过。
信息:创建用户Bean:边界_Serializable@691ae9e7
信息:认证测试自动通过。
信息:认证测试自动通过。
信息:认证测试自动通过。
信息:创建用户Bean:边界_Serializable@391115ac
信息:认证测试自动通过。
信息:认证测试自动通过。
信息:认证测试自动通过。
有状态会话bean(SFSB)并不是您所想象的那样。您似乎认为它们的行为在某种程度上类似于会话范围内的JSF托管bean。这是不真实的。EJB中的术语“会话”的含义与您所想到的HTTP会话完全不同

EJB中的“会话”必须在事务上下文中解释。事务(基本上是DB会话)在SFSB情况下只要客户端存在就存在。在您的特定示例中,SFSB的客户机不是webbrowser,而是JSF管理的bean实例本身,正是注入SFSB的实例。由于您已将JSF托管bean放在请求范围内,因此将在每个HTTP请求上与JSF托管bean一起重新创建SFSB

例如,尝试将JSF托管bean放在视图范围中。例如,视图范围对于同一页面上的多步骤表单非常有用。每次视图回发到自身时,相同的JSF托管bean实例将被重用,并且该实例允许您访问与创建bean时相同的SFSB的实例,该实例不是在别处共享的。SFSB事务的存在时间与客户端(视图范围的JSF托管bean)的存在时间相同

无状态会话bean(SLSB)可以在其他地方共享,但这并不重要,因为它打算被视为无状态会话bean。此“功能”节省了容器创建和存储它们的时间和内存。容器只能有一个池。更重要的是,注入视图、会话或应用程序范围的JSF托管bean中的SLSB实例不一定需要在每个HTTP请求上引用与JSF托管bean创建期间完全相同的实例。它甚至可以是完全不同的实例,具体取决于容器池中的可用实例。事务的生存期(默认情况下)与SLSB上的单个方法调用一样长

也就是说,SFSB不适用于“记住登录用户”的特定情况。它“更安全”真的毫无意义。只需将JSF托管bean放在会话范围内,让它自己记住登录的用户,并使用SLSB执行任何业务操作(例如与DB交互),并且仅当您需要真正的有状态会话bean时才使用SFSB(我假设您现在了解它们的确切含义:)

另见:

根据我的调查和使用情况,EJBSFSB不适用于web应用程序,因为JSF、Spring提供了完整的注释来保持每个用户的会话。但在运行webservice和RPC方法调用所需的应用程序的情况下,EJBSFSB需要保持每个用户的会话(分段)。

谢谢,这更有意义。以下是我读到的关于我为什么要这样做的文章。第二篇是一篇优秀的文章。我现在知道你是从哪里来的“更安全”。我认为您现在很好地认识到,应该在事务上下文中解释它,而不是在webapp上下文中。第一种观点很有道理,但总体解释和示例都很薄弱。我建议作为一个起点。太好了,我喜欢一本好书。再次感谢您的额外反馈。如果SFSB是托管bean呢?(带命名和有状态注释)。我希望它通过请求保持状态(如@SessionScoped),但看起来情况并非如此。@gpilotino:用CDI
@SessionScoped
注释它。我只是不建议这种紧密耦合。虽然这很古老(而且回答得很好),但我认为值得一提的是,“当[您]重新部署应用程序时,它们都会被破坏”的原因是,当您使用@EJB注入有状态会话bean时,由应用程序触发@PreDestroy方法,否则它就挂在那里。这就是为什么您的输出从未命中
cleanup()
。另见
@Named(value = "loginController")
@RequestScoped
public class LoginController implements Serializable {

    @EJB
    private UserBeanLocal userBean;

    public boolean isAuthenticated() {
        return userBean.isAuthenticated();
    }

}
@Stateful
public class UserBean implements UserBeanLocal, Serializable {

    boolean authenticated = false;

    @PostConstruct
    @PostActivate
    public void setup(){
        System.out.println("##### Create user Bean: "+this.toString());
    }

    @Override
    public boolean isAuthenticated() {
        System.out.println("########## Authentication test is automatically passing.");
        authenticated = true;//hard coded for simplicity.
        return authenticated;
    }     

    @PrePassivate
    @PreDestroy
    public void cleanup(){
        System.out.println("##### Destroy user Bean");
    }

}