bra*_*orm 7 jsf ejb java-ee cdi managed-bean
我正在阅读JBoss中的这个示例,其中使用@RequestScoped
bean备份JSF page
来传递用户凭据信息,然后将其保存在@sessionScoped bean
.以下是JBoss文档的示例.
@Named @RequestScoped
public class Credentials {
private String username;
private String password;
@NotNull @Length(min=3, max=25)
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
@NotNull @Length(min=6, max=20)
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
Run Code Online (Sandbox Code Playgroud)
JSF表格:
<h:form>
<h:panelGrid columns="2" rendered="#{!login.loggedIn}">
<f:validateBean>
<h:outputLabel for="username">Username:</h:outputLabel>
<h:inputText id="username" value="#{credentials.username}"/>
<h:outputLabel for="password">Password:</h:outputLabel>
<h:inputSecret id="password" value="#{credentials.password}"/>
</f:validateBean>
</h:panelGrid>
<h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/>
<h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/>
</h:form>
Run Code Online (Sandbox Code Playgroud)
用户实体:
@Entity
public class User {
private @NotNull @Length(min=3, max=25) @Id String username;
private @NotNull @Length(min=6, max=20) String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String setPassword(String password) { this.password = password; }
}
Run Code Online (Sandbox Code Playgroud)
SessionScoped bean
@SessionScoped @Named
public class Login implements Serializable {
@Inject Credentials credentials;
@Inject @UserDatabase EntityManager userDatabase;
private User user;
public void login() {
List<User> results = userDatabase.createQuery(
"select u from User u where u.username = :username and u.password = :password")
.setParameter("username", credentials.getUsername())
.setParameter("password", credentials.getPassword())
.getResultList();
if (!results.isEmpty()) {
user = results.get(0);
}
else {
// perhaps add code here to report a failed login
}
}
public void logout() {
user = null;
}
public boolean isLoggedIn() {
return user != null;
}
@Produces @LoggedIn User getCurrentUser() {
return user;
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是
1)将@RequestScoped
豆子注入@SessionScoped
豆中.在一个实例上设置的凭证信息RequestScoped
与注入@SessionScoped
bean 的相同的保证是什么.为什么不@RequestScoped
注入池甚至是新实例?
2)为什么要给豆@SessionScoped
而不给@Stateful
.我想@Stateful
会在这里工作.
3)@sessionScoped
bean 的生命周期是如何管理的?那是什么时候被摧毁了?如果我导航到另一个JSF
页面,如果我提取信息currentUser.userName
,我将检索我在JSF
用于登录的第一页上设置的相同信息.(上面的步骤1)
4)如果我没有指定@RequestScoped
,则Credentials bean获取@Dependent
作为defualt范围的范围.在文档中提到,设置任何实例变量@Dependent
会立即丢失.但我不明白为什么?事实上,这提示我有关@Dependent
范围的使用范围的问题?
谢谢
编辑 感谢kolossus提供详细而优秀的答案.为了更好地理解,我需要对你的一些要点做一些澄清
@RequestScoped
bean 支持的JSF,则每个客户端都可以@RequestScoped
从池中处理一个bean 实例.实际上,两个客户端实际上并不在直接实例上工作,而是间接引用作为代理的单个实例.客户端使用此代理执行所有方法调用或事务.所以代理持有这个间接引用多长时间?也就是说,在我上面的例子中,@RequestScoped
bean(Credentials
)的实例变量是在JSF中设置的.但事实是,实例变量的这种设置通过代理间接发生在@RequestScoped bean的一个实例上.但是当这个实例被注入SessionScoped
bean时,它是被注入的代理吗?由于生命周期SessionScoped
是针对客户端和应用程序之间建立的会话,因此代理也会在此生命周期内生存.这是否意味着这single instance of @RequestScoped bean
是绑定SessionScoped
的,@RequestScoped
bean实例或其代理的生命周期是由SessionScoped
bean 的生命周期决定的?在
@RequestScoped
豆被注入@SessionScoped
豆.什么是在RequestScoped的一个实例上设置的凭证信息与注入的相同的保证@SessionScopedbean
.为什么不@RequestScoped
注入池甚至是新实例?
这是合法的,这要归功于CDI实际获取对所请求的bean的引用的方式:客户端代理.从CDI规范
注入的引用或通过编程查找获得的引用通常是上下文引用.对具有正常范围的bean的上下文引用[...]不是对bean的上下文实例的直接引用[...] .相反,上下文引用是客户端代理对象 客户端代理实现/扩展bean的部分或全部bean类型,并将所有方法调用委托给bean的当前实例 ...
这种间接有很多原因:
- 容器必须保证在调用对正常作用域的bean的任何有效注入引用时,调用始终由注入bean的当前实例处理.在某些情况下,例如,如果将请求范围的bean注入到会话范围的bean或servlet中,则此规则需要间接引用
同样来自这篇DZone CDI文章:
CDI通过使用代理来处理具有不匹配范围的bean的注入.因此,您可以将请求范围的bean注入到会话范围的bean中,并且引用在每个请求上仍然有效,因为对于每个请求,代理重新连接到请求范围bean的实时实例
这意味着,代理在每个注入点代替真实的东西.代理通过扩展/实现它应该模仿的类型的祖先树来模仿注入点处声明的类型.在您现在实际需要使用该对象时,代理会对当前对话中请求的bean的现有实例执行基于上下文的查找.这是一个请求范围的对象,您可以保证在当前对话/上下文中只有一个实例.
为什么bean被赋予@SessionScoped而不是@Stateful.我猜@Stateful会在这里工作.
@Stateful
在这里不行,就像我在这里说的那样,它们并不便宜; 除非你真的需要,坚持使用香草HttpSession
.更不用说一旦SFSB的客户端释放了它被销毁的bean,即SFSB没有绑定到当前会话,@SessionScoped
就是这样的事实.
@sessionScoped bean的生命周期是如何管理的?那是什么时候被摧毁了?如果我导航到另一个JSF页面,如果我提取诸如currentUser.userName之类的信息,我将检索我在用于登录的第一个JSF页面上设置的相同信息.(上面的步骤1)
取决于@SessionScoped
你所指的:javax.faces.bean.SessionScoped
直接绑定到当前HttpSession
/浏览器会话,所以它会在死亡时终止; 然而, JBoss 意味着javax.enterprise.context.*
在"上下文"死亡之前,scoped bean实际上并没有去任何地方
实际上,在整个上下文被销毁之前,无法从上下文中删除bean
可以想象@Dependent
你可以使用任何方法局部变量:它只有在它的父构造存在的情况下才有用.话虽这么说,但最好的用途不是支持JSF视图.它最有用的应用程序是覆盖在bean上指定的范围,即ad-hoc.使用您当前的示例,我可以在我的应用程序中的其他位置使用以下内容:
@Inject @New Login aDependentLoginBean; //implicit @Dependent scope applied
@Inject Login aSessionScopedLoginBean; //standard Login bean's scope applied
Run Code Online (Sandbox Code Playgroud)
与@New一起,您可以重新利用任何其他bean@Dependent
有关:
归档时间: |
|
查看次数: |
4190 次 |
最近记录: |