将值传递给注入的 EJB

Pass value to injected EJB

我有一个由两个 bean 组成的 EJB 应用程序,ServiceEJB(Web 层)和 BusinessEJB(业务层),其中 BusinessEJB 被注入 ServiceEJB .

ServiceEJB从浏览器接收 HTTP 请求,调用 BusinessEJB 中的方法,获取结果,并发送 HTTP 响应。

此外,ServiceEJB 可以访问 HttpSession 对象,其中存储了登录用户的 userIdBusinessEJB无权访问 HttpSession 对象。

应用程序需要记录消息(例如使用sl4j/logback)。它可以在 ServiceEJBBusinessEJB 方法中记录消息,并且当它记录消息时,它必须在日志条目中包含会话的 userId

由于 BusinessEJB 没有 userId,因此需要从 ServiceEJB 获取它。问题是实现这一目标的最佳方式是什么。我不想做的是在 BusinessEJB 中的每个方法中添加一个 userId 字段作为参数,因为其中有很多 ServiceEJBs 和 BusinessEJBs应用程序(以及由 BusinessEJB 调用的也会生成日志条目的其他 bean),我不想用 userId 字段污染应用程序。相反,我可以在 EJB 级别有一个 userId 字段,但是如何填充它们呢?有没有办法通过注释来实现这一点?欢迎任何建议。

@Produces({MediaType.APPLICATION_JSON})
@Consumes({MediaType.APPLICATION_JSON})
@Stateless
public class ServiceEJB {

    @Context
    HttpServletRequest httpRequest;

    @Inject
    private BusinessEJB bean;

    private String userId;

    @Path("someurl")
    public Response someMethod1() {
       final HttpSession session = httpRequest.getSession();
       // get the userId from the session

       String s = bean.someMethod2();

       // return Response
    }
}

@Stateless
public class BusinessEJB {

  private String userId;

  public String someMethod2() {
     // ....  log an entry with userId
     return "something";
  }   
}

创建请求范围的 CDI bean,即 UserContext

将其注入到两个 EJB 中。

ServiceEJB 中设置用户 ID 并在 BusinessEJB 中读取它。

几个pointers/comments:

  1. 如果与应用程序服务器安全集成,则用户名在任何组件中都可用。 EJB 可以通过在 EJBContext 的注入变体上调用 getCallerPrincipal() 来获取它,这里是 javax.ejb.SessionContext:

    @Resource
    private SessionContext sessionCtx;
    

    Servlet 可以从 HttpServletRequest.getUserPrincipal() 中检索主体。 JAX-RS 组件(ServiceEJB)可以从 javax.ws.rs.core.SecurityContext.getUserPrincipal().

    中检索它

    您有什么理由不与应用程序服务器安全性集成吗?

  2. 如果您有充分的理由不与应用程序服务器安全集成,我会建议 的解决方案变体。变化是从应用于所有资源的过滤器(servlet 过滤器或 JAX-RS ContainerRequestFilter)设置用户数据,这样您就不必担心在多个地方设置它。

  3. 如果您只需要用户 ID 进行日志记录,我建议您看一下 slf4j 中映射诊断上下文 (MDC) 的概念。使用它,您可以在请求开始时尽早设置用户 ID,并使其可用于此后的所有日志记录语句。