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

The*_*heo 7 java java-ee cdi

我想@Inject @Current User在所有层(即web层,EJB层)中使用当前用户.为此,我有以下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{}
Run Code Online (Sandbox Code Playgroud)

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

@Stateless
public class SomeBackendService {
   @Inject @Current
   private User user;
}
Run Code Online (Sandbox Code Playgroud)

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

Arj*_*jms 4

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

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

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

附注

如果对于层,您实际上指的是作为 EAR 一部分的 Web 和 EJB 模块中的模块,那么情况会稍微复杂一些,因为 CDI 并不总是按预期在模块之间工作(尤其是在 JBoss AS 中)。部分原因是“应用程序”的含义不明确,因此应用程序范围属于 EAR 之内。