JSF请求作用域bean继续在每个请求上重新创建新的有状态会话bean吗? [英] JSF request scoped bean keeps recreating new Stateful session beans on every request?

查看:144
本文介绍了JSF请求作用域bean继续在每个请求上重新创建新的有状态会话bean吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JSF,PrimeFaces,Glassfish和Netbeans构建我的第一个Java EE应用程序。因为我是新手,所以我可能会接近核心问题。

I'm building my first Java EE application using JSF, PrimeFaces, Glassfish and Netbeans. Because I'm new, it's possible I'm approaching the core problem wrong.

核心问题:我想安全地维护用户的信息。关于是否应该在JSF会话bean或有状态会话EJB中维护它似乎存在冲突的想法。我正在尝试使用有状态会话EJB,因为它更安全。

Core problem: I want to maintain user's information securely. There seems to be conflicting ideas on whether it should be maintained in a JSF session bean or a stateful session EJB. I'm trying to use a stateful session EJB because it is more secure that way.

问题是我的应用程序似乎在创建该bean的多个实例时期望它创造一个并重新使用它。如果我刷新页面,它会运行 @PostConstruct @PostActivate 3次,所有这些都有不同的实例。然后,当我重新部署应用程序时,它们都会被破坏。

The problem is that my application seems to be creating multiple instances of that bean when I expect it to create one and re-use it. If I refresh the page it runs the @PostConstruct and @PostActivate 3 times, all of them with a different instances. Then they all get destroyed when I re-deploy the application.

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

Did I misunderstand how it should work or is something wrongly configured?

我会尝试展示一个修剪代码示例:

I'll try to show a trimmed down code sample:

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>

LoginController

@Named(value = "loginController")
@RequestScoped
public class LoginController implements Serializable {

    @EJB
    private UserBeanLocal userBean;

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

}

UserBean (不包括 UserBeanLocal 界面)

@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");
    }

}

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

Finally, here is the Glassfish output after refreshing three times:

INFO: ##### Create user Bean: boundary._UserBean_Serializable@2e644784
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@691ae9e7
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ##### Create user Bean: boundary._UserBean_Serializable@391115ac
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.
INFO: ########## Authentication test is automatically passing.


推荐答案

有状态会话bean(SFSB)并不完全是你的意思认为他们是。您似乎认为它们的行为类似于会话作用域的JSF托管bean。这是不真实的。 EJB中的术语会话与您考虑过的HTTP会话具有完全不同的含义。

Stateful session beans (SFSB) are not exactly what you think they are. You seem to think that they behave somehow like session scoped JSF managed beans. This is untrue. The term "session" in EJBs has an entirely different meaning than the HTTP session which you've had in mind.

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

The "session" in EJBs must be interpreted in transactional context. The transaction (basically, the DB session) lives in case of SFSB as long as the client lives. The SFSB's client is in your particular example not the webbrowser, but the JSF managed bean instance itself, exactly the one where the SFSB is been injected. Since you have put the JSF managed bean in the request scope, the SFSB will be recreated on every HTTP request together with the JSF managed bean.

作为示例,尝试将JSF托管bean放在视图范围内。例如,视图范围对于同一页面上的多步骤表单非常有用。每当视图回发到自身时,那么将重用相同的JSF托管bean实例,并且此实例允许您访问SFSB的相同实例,就像创建bean时一样,这是<强>不在别处分享。只要客户端(视图作用域的JSF托管bean)存在,SFSB事务就会存在。

As an example, try to put the JSF managed bean in the view scope. The view scope is useful for a multi-step form on the same page, for example. Everytime when the view postbacks to itself, then the same JSF managed bean instance will be reused and this instance gives you access to the same instance of the SFSB as it is when the bean was created, which is not shared elsewhere. The SFSB transaction lives as long as the client (the view scoped JSF managed bean) lives.

无状态会话bean(SLSB)可以在别处共享,但那不应该'无论如何,因为它意图被视为无国籍。这个功能节省了容器时间和内存来创建和存储它们。容器可以只有一个池。更重要的是,在视图,会话或应用程序范围内的JSF托管bean中注入的SLSB实例不一定需要在每个HTTP请求中引用与在JSF托管bean创建期间完全相同的实例。它甚至可以是完全不同的实例,具体取决于容器池中的可用实例。只要对SLSB上的单个方法调用,事务就会生效(默认情况下)。

A stateless session bean (SLSB) can be shared elsewhere, but that shouldn't matter as it's intented to be treated as stateless anyway. This "feature" saves the container time and memory to create and store them. The container can just have a pool of them. Even more, the SLSB instance which is been injected in a view, session or application scoped JSF managed bean does not necessarily need to refer exactly the same instance on every HTTP request as it was during JSF managed bean's creation. It can even be a completely different instance, depending on the available instances in the container's pool. The transaction lives (by default) as long as a single method call on the SLSB.

这就是说,SFSB不适合您记住已记录 - 的特定情况在用户。它更安全真的没有意义。只需将JSF托管bean放在会话范围内,让它自己记住登录用户,并使用SLSB执行任何业务操作(例如与数据库交互),并仅在需要真正的有状态会话bean(我假设您现在了解它们究竟是什么:) :)。

That said, a SFSB is unsuitable for your particular case of "remembering a logged-in user". That it's "more secure" makes really no sense. Just put the JSF managed bean in the session scope and let it remember the logged-in user by itself and make use of a SLSB to do any business actions (such as interacting with the DB) and use SFSB only when you want a real stateful session bean (I assume that you now understand what exactly they are :) ).

  • When is it necessary or convenient to use Spring or EJB3 or all of them together?
  • Why Stateless session beans?
  • JSF Service Layer

这篇关于JSF请求作用域bean继续在每个请求上重新创建新的有状态会话bean吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆