我应该如何在我的 RESTful JAX-RS Web 服务中记录未捕获的异常?
我有一个使用泽西岛和杰克逊在Glassfish 3.1.2下运行的RESTful Web服务:
@Stateless
@LocalBean
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("users")
public class UserRestService {
private static final Logger log = ...;
@GET
@Path("{userId:[0-9]+}")
public User getUser(@PathParam("userId") Long userId) {
User user;
user = loadUserByIdAndThrowApplicableWebApplicationExceptionIfNotFound(userId);
return user;
}
}
对于预期的异常,我抛出相应的 WebApplicationException
,并且我对发生意外异常时返回的 HTTP 500 状态感到满意。
我现在想为这些意外的异常添加日志记录,但是尽管进行了搜索,也无法找出我应该如何做到这一点。
徒劳的尝试
我尝试过使用Thread.UncaughtExceptionHandler
,并且可以确认它是否在方法主体内部应用,但其方法从未被调用,因为其他内容是在未捕获的异常到达我的处理程序之前处理它们。uncaughtException
其他想法: #1
我看到一些人使用的另一个选项是AlexceptionMapper
,它捕获所有异常,然后过滤掉WebApplicationExceptions:
@Provider
public class ExampleExceptionMapper implements ExceptionMapper<Throwable> {
private static final Logger log = ...;
public Response toResponse(Throwable t) {
if (t instanceof WebApplicationException) {
return ((WebApplicationException)t).getResponse();
} else {
log.error("Uncaught exception thrown by REST service", t);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
// Add an entity, etc.
.build();
}
}
}
虽然这种方法可能有效,但在我看来,这就像滥用了 ExceptionMappers 应该用于什么,也就是说,将某些异常映射到某些响应。
其他想法: #2
大多数示例 JAX-RS 代码直接返回响应
对象。按照这种方法,我可以将我的代码更改为类似下面的代码:
public Response getUser(@PathParam("userId") Long userId) {
try {
User user;
user = loadUserByIdAndThrowApplicableWebApplicationExceptionIfNotFound(userId);
return Response.ok().entity(user).build();
} catch (Throwable t) {
return processException(t);
}
}
private Response processException(Throwable t) {
if (t instanceof WebApplicationException) {
return ((WebApplicationException)t).getResponse();
} else {
log.error("Uncaught exception thrown by REST service", t);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
// Add an entity, etc.
.build();
}
}
但是,我对走这条路持谨慎态度,因为我的实际项目并不像此示例那样简单,我必须一遍又一遍地实现相同的模式,更不用说必须手动构建响应了。
我该怎么办?
有没有更好的方法来为未捕获的异常添加日志记录?有没有一种“正确”的方法来实现这一点?