【问题标题】:Why would @SessionsScoped EJB be shared accross all users?为什么@SessionsScoped EJB 会在所有用户之间共享?
【发布时间】:2012-08-02 04:35:07
【问题描述】:

我确定我在这里遗漏了一些东西。但我有一个会话范围的 EJB:

@javax.inject.Named
@javax.ejb.Stateful
@javax.enterprise.context.SessionScoped
public class Authenticator implements Serializable
{
...

我希望每个 HTTP 会话都会看到这个 EJB 的不同实例?

但是,当从多个浏览器(包括在不同的机器上)访问一个 JSF 页面时,

#{authenticator.hashCode()}

在所有这些上都是相同的(当然还有类的成员属性)。为什么会这样? (我已经尝试删除@Stateful 注释,但同样适用)。

我正在使用 JBoss AS 7.1.0。

编辑:我发现在 Authenticator 上创建一个方法:

public void getHashCode()
{
   return hashCode();
}

并在 EL 中将其引用为

#{authenticator.hashCode()}

表明我实际上正在访问 bean 的不同实例;但这是为什么呢?我不明白为什么这两个 EL 表达式的结果会不同。

【问题讨论】:

  • Authenticator 类是否具有会话独有的字段,例如会话 ID?如果不是,则没有任何迹象表明它们完全相同的实例,而是两个不同的实例,它们的字段具有相同的值。
  • 这就是我使用 hashCode 的目的 - 这应该是不同的。此外,如果您在一个浏览器上登录,则会在另一个浏览器上显示已登录的用户,这首先提醒了我这个问题。
  • 您的 bean 中是否有静态成员?
  • 是的,我认为这是成员属性的问题(还有一个在字段上注释 @Produces 而不是 get 方法)。但是,我仍然不清楚为什么 hashCode() 返回相同的值 - 这不是静态的,是吗?
  • 不同的对象不需要有不同的哈希值。 return 0; 是一个完全有效的 hashCode() 实现,虽然不是很好。也就是说,您可能会遇到代理。您的第一个实验可能是获取代理的哈希值。您的第二个实验通过对象实例并返回其哈希值。我不确定为什么代理会在这种情况下发挥作用,但我认为这种行为很合适。

标签: jakarta-ee return java-ee-6 cdi


【解决方案1】:

您看到的行为与未经身份验证的 HTTP 会话一致,因此我假设您没有设置身份验证。因此,如果您将以下内容添加到您的代码中

@Resource
private EJBContext ctx;

public Principal getPrincipal() {
    return this.ctx.getCallerPrincipal();
}

并在您的测试页面中添加

<h:outputText value="#{test.principal}" />
<h:outputText value="#{test.hashCode()}" />

您将始终看到相同的输出。对于 EJB 容器,由于在本地调用中客户端实际上是 servlet 容器,所以您将始终看到相同的输出 ANONYMOUS{your hash code here}。每个未经身份验证的 http 会话都算作一个 ANONIMOUS EJB 会话,因为客户端始终相同 - 您的 servlet 容器。

尝试设置某种身份验证,您会看到预期的行为,至少我在 Glassfish3+ 环境中是这样。

【讨论】:

    猜你喜欢
    • 2016-02-23
    • 1970-01-01
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多