在运行时,如何将@RequestScoped bean实例提供给@SessionScoped bean? [英] how is the @RequestScoped bean instance provided to @SessionScoped bean in runtime here?

查看:145
本文介绍了在运行时,如何将@RequestScoped bean实例提供给@SessionScoped bean?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在 JBoss 其中 @RequestScoped bean备份 JSF页面用于传递用户凭据信息,然后将其保存在一个 @sessionScoped bean
以下是 JBoss文档的示例。

I am reading through this example in JBoss where a @RequestScoped bean backing up JSF page is used to pass the user credential information which is then saved in a @sessionScoped bean. Here is the example take from JBoss docs.

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

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>

用户实体:

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

SessionScoped bean

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;
   }
}

我的问题是

1) @RequestScoped bean注入 @SessionScoped bean。在 RequestScoped 的一个实例上设置的凭据信息与注入 @SessionScoped bean相同的保证是什么。为什么不从池中注入不同的 @RequestScoped ,甚至是一个新的实例?

1) The @RequestScoped bean gets injected into @SessionScoped bean. What is the guarantee that the credential information set on one instance of RequestScoped is the same that is injected into @SessionScopedbean. why not a different @RequestScoped from pool gets injected or even a new instance?

2)为什么是bean给定 @SessionScoped 而不是 @Stateful 。我想 @Stateful 将在这里工作。

2)why is the bean given @SessionScoped but not @Stateful. I guess @Stateful will work here.

3)生活周期如何 @ sessionScoped bean管理?那是什么时候被毁了?如果我导航到另一个 JSF 页面,其中如果我提取信息,例如 currentUser.userName ,我将检索我在我的第一个 JSF 页面上设置的相同信息(上面的步骤1)

3)how is the lifecycle of @sessionScoped bean managed? That is when does it gets destroyed ?. If I navigate to a different JSF page in which if I pull the information such as currentUser.userName, will I retrieve the same information I set on my first JSF page used to log in. (step 1 above)

4)如果我没有指定 @RequestScoped ,则Credentials bean将获取作为defualt作用域的 @Dependent 范围。在 docs 中提及设置 @Dependent 的任何实例变量立即丢失。但我不明白为什么?事实上,这提示我的问题是什么使用 @Dependent 范围将是?

4) If I don't specify @RequestScoped, then the Credentials bean get the @Dependent scope which is the defualt scope. It is mentioned in the docs that setting any instance variables of a @Dependent gets lost immediately. But I don't understand why? In fact, this prompts me the question of what use of @Dependent scope will be ?

谢谢

编辑
感谢kolossus的详细和优秀的答案。对于一些@requestScoped bean,有一个可用的实例池,我需要一些更多的澄清,以便更好地了解

EDIT Thanks kolossus for detailed and excellent answer. I need a little more clarifications on some of your points for better understanding


    <这被交给客户。现在如果我有两个客户端访问由$ code> @RequestScoped bean支持的JSF,那么每个客户端都可以在一个 @RequestScoped bean。实际上,这两个客户端实际上并不直接在直接实例上工作,而是直接引用该代理的单一实例。客户端使用此代理执行所有方法调用或事务。那么代理持有这个间接引用多长时间?也就是说,在上面的例子中,在JSF中设置了 @RequestScoped bean( Credentials )的实例变量。但真正的事实是,实例变量的这种设置通过代理间接地发生在@RequestScoped bean的一个实例上。但是当这个实例被注入到 SessionScoped bean中时,是否被注入代理?由于 SessionScoped 的生命周期是针对在客户端和应用程序之间建立的会话,代理是否还会在此一生中生效。这是否意味着@RequestScoped bean 的单一实例绑定到 SessionScoped ,生命周期 @RequestScoped bean实例或其代理由 SessionScoped bean的生命周期确定
  1. For a @requestScoped bean, there are is a pool of instances available which gets handed over to clients. Now if I have two clients accessing a JSF which is backed by a @RequestScoped bean, each client gets to work on one instance of @RequestScoped bean from the pool. In fact, both the clients do not actually work on the direct instance, but an indirect reference to the that single instance which is the proxy here. clients do all method calls or transactions using this proxy. so how long does the proxy holds this indirect reference? That is, in my example above, instance variables of @RequestScoped bean (Credentials) are set in JSF. but the true fact is that, this setting of instance variables happen to one instance of @RequestScoped bean indirectly through proxy. But when this instance is injected into SessionScoped bean, is it the proxy that gets injected? Since the lifecycle of SessionScoped is for a session established between client and application, does the proxy also live during this lifetime. Does that mean this single instance of @RequestScoped bean is bound to SessionScoped and the lifecycle of @RequestScoped bean instance or its proxy is determined by the lifecycle of SessionScoped bean?


推荐答案



@RequestScoped bean注入 @SessionScoped bean。在RequestScoped的一个实例上设置的凭据信息与注入 @SessionScopedbean 中相同的保证是什么。为什么不能从池中注入不同的 @RequestScoped 甚至一个新的实例?

The @RequestScoped bean gets injected into @SessionScoped bean. What is the guarantee that the credential information set on one instance of RequestScoped is the same that is injected into @SessionScopedbean. why not a different @RequestScoped from pool gets injected or even a new instance?

这是合法的,感谢CDI实际获取对所请求的bean的引用的方法:客户端代理。从 CDI规格

This is legal, thanks to the means by which CDI actually obtains references to a requested bean: client proxies. From the CDI spec



注入的引用或通过编程查找获得的引用通常是上下文引用。上下文引用对于具有正常范围[...]的bean,不是直接引用bean的上下文实例[...],而是上下文引用是客户端代理对象
客户端代理实现/扩展了bean的一些或所有bean类型,并将所有方法调用委托给当前bean实例。

An injected reference, or reference obtained by programmatic lookup, is usually a contextual reference.A contextual reference to a bean with a normal scope[...], is not a direct reference to a contextual instance of the bean[...].Instead, the contextual reference is a client proxy object A client proxy implements/extends some or all of the bean types of the bean and delegates all method calls to the current instance of the bean...

这个间接的原因有很多:


  • 容器必须保证当调用正常范围的bean的任何有效注入引用时,调用始终由当前的注册实例进行处理扁豆在某些情况下,例如,如果将一个请求作用域bean注入到一个会话作用域bean或一个servlet中,则此规则需要间接引用

  • The container must guarantee that when any valid injected reference to a bean of normal scope is invoked, the invocation is always processed by the current instance of the injected bean. In certain scenarios, for example if a request scoped bean is injected into a session scoped bean, or into a servlet, this rule requires an indirect reference

另外从这个DZone CDI文章


CDI通过使用代理处理注入不匹配的范围的bean。因此,您可以将一个请求作用域bean注入会话作用域bean,并且该引用在每个请求上仍然有效,因为对于每个请求,代理重新连接到请求作用域bean的实时实例

CDI handles the injection of beans with mismatched scopes through the use of proxies. Because of this you can inject a request scoped bean into a session scoped bean and the reference will still be valid on each request because for each request, the proxy re-connects to a live instance of the request scoped bean

这意味着代理代替每个注入点的真实事物。该代理通过扩展/实现它应该模仿的类型的祖先树,来模拟在注入点处声明的类型。当时您现在实际上需要使用对象,代理对当前会话中所请求的bean的现有实例执行基于上下文的查找。这是一个请求范围的对象,您保证在当前会话/上下文中只有一个实例。

What this means is that, a proxy is substituted for the real thing at each injection point. The proxy mimics the type declared at the injection point by extending/implementing the ancestor tree of the type it's supposed to be mimicking. At the time you now actually require use of the object, the proxy performs a context-based lookup for an existing instance of the requested bean within the current conversation. This being a request-scoped object, you're guaranteed to have exactly one instance within the current conversation/context.


为什么bean被赋予@SessionScoped但不是@Stateful。我想@Stateful会在这里工作。

why is the bean given @SessionScoped but not @Stateful. I guess @Stateful will work here.

@Stateful 就像我在这里所说的那样,他们并不便宜;除非你真的需要,坚持使用香草 HttpSession 。更不用说,一旦SFSB的客户端释放了bean,它就被破坏了,即SFSB没有绑定到当前会话, @SessionScoped 是。

@Stateful would not work here, like I stated here, they are not cheap; unless you really need to, stick with vanilla HttpSession. Not to mention the fact that once the client of the SFSB releases the bean it's destroyed, i.e. the SFSB is not tied to the current session,@SessionScoped is.


@sessionScoped bean的生命周期是如何管理的?那是什么时候被毁了?如果我导航到不同的JSF页面,其中如果我提取的信息如currentUser.userName,我将检索与我在用于登录的第一个JSF页面上设置的相同的信息(上面的步骤1)

how is the lifecycle of @sessionScoped bean managed? That is when does it gets destroyed ?. If I navigate to a different JSF page in which if I pull the information such as currentUser.userName, will I retrieve the same information I set on my first JSF page used to log in. (step 1 above)

取决于您所指向的 @SessionScoped javax.faces .bean.SessionScoped 直接绑定到当前的 HttpSession / browser会话,所以当它死机时它被终止;然而,JBoss 意味着 javax.enterprise.context。* 范围限制的bean在上下文死亡之前并不会去任何地方

Depends on which @SessionScoped you're referring to: javax.faces.bean.SessionScoped is tied directly to the current HttpSession/browser session, so it's terminated whenever that dies; JBoss however implies that javax.enterprise.context.* scoped beans don't actually go anywhere until the "context" dies


在整个上下文被销毁之前,实际上没有办法从上下文中删除一个bean。

There's actually no way to remove a bean from a context until the entire context is destroyed


  • code> @Dependent 就像你所使用的任何方法局部变量一样:只要它的父构造是有用的,它就是有用的。话虽如此,最好不要用于支持JSF视图。这是最有用的应用程序覆盖了在ad hoc上指定的范围。使用您当前的示例,我可以在我的应用程序中找到以下内容:

  • Think of @Dependent as you would any method-local variable: it's only useful as long as it's parent construct is around. That being said, it's best use is not for backing a JSF view. It's most useful application is overriding the scope that's specified on a bean, ad-hoc. Using your current example, I can have the following somewhere else in my application:

    @Inject @New Login aDependentLoginBean; //implicit @Dependent scope applied
    @Inject Login aSessionScopedLoginBean;  //standard Login bean's scope applied
    

    @ New ,您可以重新调整任何其他bean为 @Dependent

    Together with @New, you could repurpose any other bean to be @Dependent






    相关: / strong>


    Related:

    • Is it possible to @Inject a @RequestScoped bean into a @Stateless EJB?

    这篇关于在运行时,如何将@RequestScoped bean实例提供给@SessionScoped bean?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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