2013-10-15 55 views
0

我想通过拦截器对EJB调用应用通用日志记录。此日志记录应该记录bean的安全主体。该方法使用MDC并将主体推送到MDC,并在方法调用完成时将其删除。具有日志和嵌套EJB调用的EJB拦截器

但是,当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第二个日志语句没有用户了,因为用户键已经从MDC通过Bean2截取的最后清障:

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. 

回答

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); 
    } 
} 
+0

但是对于这个建议我绝不会删除MDC中的用户。 – dweisser

+1

这很重要吗?如果在调用方法之前没有用户,那么在MDC中的调用USER_KEY将等于null之后。自然地,代码可以被增强,以便它从地图上移除,但是这个想法保持不变。 – Mareen