0

我正在尝试通过拦截器为 EJB 调用应用常规日志记录。此日志记录应记录 bean 的安全主体。该方法使用 MDC 并将主体推送到 MDC 并在方法调用完成时将其删除。

但是,当在 EJB 中进行 EJB 方法调用时,这种方法会失败。请参阅下面的演示代码。有没有解决这个问题的解决方案或更好的方法?

public class LoggingInterceptor {

    @Resource
    protected SessionContext sessionCtx;

    @AroundInvoke
    public Object intercept(InvocationContext ctx) throws Exception {
        Principal principal = sessionCtx.getCallerPrincipal();
        if (principal != null) {
            MDC.put("USER_KEY", principal.getName());
        }
        try {
            return ctx.proceed();
        } finally {
            MDC.remove("USER_KEY");
        }
    }
}

现在我尝试将它与会话 bean 一起使用,如下所示:

@Stateless
@Interceptors(LoggingInterceptor.class)
public class Bean1 {

    private static Logger logger = Logger.getLogger(Bean1.class);

    @Resource
    Bean2 bean2;

    public String doSomething() {
        logger.debug("Step1.");
        bean2.doMore();
        logger.debug("Step2.");

和豆2:

@Stateless
@Interceptors(LoggingInterceptor.class)
public class Bean2 {

    private static Logger logger = Logger.getLogger(Bean2.class);

    public String doMore() {
        logger.debug("Step in Bean2.");

当直接调用 Bean2 时,日志记录工作:

23:53:00,093 DEBUG [Bean2] [testuser] Step in Bean2. 

但是,当调用 Bean1 时,第二个日志语句不再具有用户,因为 UserKey 已被 Bean2 的拦截的 finally-Block 从 MDC 中删除:

23:53:00,093 DEBUG [Bean1] [testuser] Step1.
23:53:00,193 DEBUG [Bean2] [testuser] Step in Bean2.
23:53:00,293 DEBUG [Bean1] [] Step2.
4

1 回答 1

2

您可以在拦截器中继续之前存储以前的主体名称。

@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
    Principal principal = sessionCtx.getCallerPrincipal();
    String previousPrincipalName = MDC.get("USER_KEY");

    MDC.put("USER_KEY", principal == null ? "" : principal.getName());

    try {
        return ctx.proceed();
    } finally {
        MDC.put("USER_KEY", previousPrincipalName);
    }
}
于 2013-10-15T11:50:16.683 回答