JSF请求作用域bean不断在每个请求上重新创build新的有状态会话bean?
我正在使用JSF,PrimeFaces,Glassfish和Netbeans构build我的第一个Java EE应用程序。 因为我是新手,所以我可能会错误地接近核心问题。
核心问题:我想要安全地维护用户的信息。 关于应该在JSF会话bean还是有状态会话EJB中维护它们似乎存在冲突。 我正在尝试使用有状态会话EJB,因为它更安全。
问题是,我的应用程序似乎创build该bean的多个实例,当我期望它创build一个并重新使用它。 如果我刷新页面,它运行@PostConstruct
和@PostActivate
3次,所有这些都使用不同的实例。 然后,当我重新部署应用程序时,它们全部被破坏。
我误解了它应该如何工作或configuration错误吗?
我将尝试显示一个裁减的代码示例:
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输出:
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托pipe的bean。 这是不真实的。 EJB中的术语“会话”与您所考虑的HTTP会话具有完全不同的含义。
EJB中的“会话”必须在事务上下文中解释。 只要客户活着,交易(基本上是数据库会话)就会在SFSB的情况下存在。 SFSB的客户端在您的具体示例中不是 webbrowser,而是JSFpipe理的bean实例本身,就是SFSB被注入的那个实例。 由于您已经将JSF托pipebean放在请求范围中,因此将在每个HTTP请求和JSF托pipebean上重新创buildSFSB。
例如,尝试将JSF托pipebean放在视图范围中。 例如,视图范围对于同一页面上的多步表单很有用。 每次当视图回传给自己时,同样的JSF托pipebean实例将被重用,这个实例可以让你访问与创buildbean时相同的SFSB实例,这个实例在其他地方是不共享的。 只要客户端(视图范围的JSF托pipebean)存在,SFSB事务就处于活动状态。
一个无状态的会话bean(SLSB)可以在其他地方共享,但是这不应该因为它被认为是无状态的。 这个“function”节省了容器的时间和内存来创build和存储它们。 容器可以只有一个池。 更有甚者,被注入到视图,会话或应用程序范围的JSF托pipebean中的SLSB实例并不一定需要在每个HTTP请求上引用与在JSF托pipebean创build期间完全相同的实例。 它甚至可以是完全不同的实例,具体取决于容器池中可用的实例。 只要在SLSB上调用一个方法,事务就会生效(默认)。
也就是说,SFSB不适合您“记住login用户”的特殊情况。 这“更安全”是没有意义的。 只需将JSF托pipebean放入会话范围中,让其自己记住login用户,并利用SLSB执行任何业务操作(例如与数据库交互),并仅在需要真实状态时才使用SFSB会话bean(我假设你现在明白他们到底是什么:))。
也可以看看:
- 什么时候使用Spring或者EJB3或者全部使用它们是必要的还是方便的?
- 为什么无状态会话bean?
- JSF服务层
据我的调查和用法了解,EJB SFSB对于Web应用程序来说并不是有用的,因为JSF,Spring提供了helfull注释来保持每个用户的会话。 但是,如果webservice和RPC方法调用调用所需的应用程序正在运行,则EJB SFSB将保持每个用户的会话(传输)。