我有一个使用 Jersey 和 Jackson 在 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 状态感到满意。
我现在想为这些意外异常添加日志记录,但尽管进行了搜索,但无法找到我应该如何处理这个问题。
徒劳的尝试
我尝试使用 aThread.UncaughtExceptionHandler
并且可以确认它已应用在方法主体内,但它的uncaughtException
方法从未被调用,因为其他东西正在处理未捕获的异常,然后它们到达我的处理程序。
其他想法:#1
我见过一些人使用的另一个选项是 an ExceptionMapper
,它捕获所有异常,然后过滤掉 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 代码Response
直接返回对象。按照这种方法,我可以将我的代码更改为:
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();
}
}
但是,我对走这条路持怀疑态度,因为我的实际项目不像这个例子那么简单,我必须一遍又一遍地实现相同的模式,更不用说必须手动构建响应。
我应该怎么办?
是否有更好的方法来为未捕获的异常添加日志记录?有没有一种“正确”的方式来实现这一点?