从EJB无状态会话bean调用CDI会话范围的生产者方法

时间:2011-08-07 13:08:15

标签: java java-ee cdi

我想在所有层(即Web层,EJB层)上使用@Inject @Current User注入当前用户。为此,我有以下CDI Producer方法:

@Named
@SessionScoped
public class UserController {
   @Resource SessionContext sessionContext;
   @EJB UserDao userDao;

   @Produces @Current
   public User getCurrentUser() {
     String username = sessionContext.getCallerPrincipal().getName();
     User user = userDao.findByUsername(username);
   }
}

@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
public @interface Current{}

现在,我想将当前用户注入EJB无状态会话bean,如下所示:

@Stateless
public class SomeBackendService {
   @Inject @Current
   private User user;
}

我的问题:当前用户对象是否总是在会话更改后重新注入,因为无状态会话bean的依赖关系通常在创建时注入一次,并且bean可能被池化并在不同的会话中使用?

3 个答案:

答案 0 :(得分:4)

虽然我没有尝试过这种确切的情况,但通常不会重新注入CDI bean。相反,注入了一个知道其上下文的代理。

通过这种机制,可以在应用程序范围的bean中注入一个会话范围的bean。应用程序作用域bean的每个用户都转到同一个bean和相同的代理,但是代理将动态地将对它的调用解析为每个用户的不同bean。

因此,即使@Stateless的范围基本上是“应用程序”,但是在“SomeBackendService”中代表User的代理仍然可以委托给正确的会话范围版本。

P.S。

如果使用 layers ,你实际上意味着模块在Web和EJB模块中属于EAR的一部分,它会变得有点复杂,因为CDI并不总是按预期工作模块(特别是在JBoss AS中)。这部分是由于“应用程序”的含义模糊,因此应用程序范围在EAR中。

答案 1 :(得分:1)

按照设计,你的无状态会话bean不应该有一个状态“User”,它无论如何都是无状态的。

如果您希望EJB具有状态,请改用@Stateful。

答案 2 :(得分:1)

是的,对于称为容器的每个业务方法,将重新注入SLSB的所有依赖项。这是在EJB 3.1规范中保证这一点的文本:

“如果会话bean使用依赖注入,容器会在创建bean实例之后,以及在bean实例上调用任何业务方法之前注入这些引用。” - 第4.3.2节

我也有这个疑问,我发布了一个解释这种情况的问题 here