更好地理解异常并在J2EE环境中进行日志记录

时间:2011-11-04 20:01:18

标签: java java-ee log4j

我正在尝试更好地理解异常处理和j2ee环境中的日志记录以重构一些遗留代码(我们使用log4j作为我们的日志记录机制)。我们当前的大多数代码在业务层上执行类似下面的代码,但是,我想切换到未经检查的异常并忽略它们,除非在某处处理它们是有意义的:

try {
    doSomething();
} catch (MyException e) {
    log.error("Exception:", e);
    throw e;
}

在业务层中抛出异常后,它会传播到表示层,再次捕获异常并通常将其包装在PortletExceptionServletException中并再次抛出。然后,它由Spring处理程序处理,该处理程序向用户显示“友好”消息。我最终只想处理我们想要显示特定错误消息的异常,而忽略其他所有内容。

问题:

  1. 是否有必要在业务层中记录异常?如果没有,那就做 我需要记录异常(尤其是未经检查的异常)?
  2. 使用log4j未记录的未捕获异常会发生什么? (如果它们仍然在控制台中打印,那么它的目的是什么 log4j的?)
  3. 我对这个过程是如何运作感到困惑......

    感谢。

    编辑:如果在外部库(Spring,Hibernate等)中发生异常,是否假设使用正在使用的任何日志记录机制打印出这些异常?在这种情况下,我想我只需要记录我的代码抛出的异常......或者我是否会离开这里?

6 个答案:

答案 0 :(得分:4)

在继续之前,请仔细查看:

  

以下是一些普遍接受的原则   异常处理:

     
      
  1. 如果您无法处理异常,请不要抓住它。
  2.   
  3. 如果您发现异常,请不要吞下它。
  4.   
  5. 尽可能接近其来源捕获异常。
  6.   
  7. 记录您捕获它的异常,除非您打算重新抛出它。
  8.   
  9. 根据您的异常处理必须具有的细粒度来构建您的方法。
  10.   
  11. 根据需要使用尽可能多的类型例外,尤其是应用程序例外。
  12.         

    第1点显然与第3点冲突。实际的解决方案是在您捕获异常的距离有多近以及在您完全失去意图之前让它落到多远之间的权衡>原始例外的内容。

         

    IBM DeveloperWorks: EJB best practices

通常建议您在业务层使用已检查的异常来处理应用程序异常。我更喜欢按照业务接口模式将业务层与用户界面和Web层分离。这将允许我将您的业务层视为服务层库,并且调用者可能希望在调用此层时以不同方式处理不同情况。这是您可能希望包含已检查异常的一个原因,因为您可以对不同的异常做出不同的反应。此外,包括已检查的异常通常有助于调用者代码更好地了解调用某些功能可能产生的不同情况。查看业务委托模式以及它如何帮助您进行异常处理可能是值得的。简而言之,business delegate pattern允许您在业务层和Web层之间创建一个非常薄的层,您可以在其中执行异常处理等操作。

无论您如何执行此操作,请确保您了解向Java EE应用程序添加应用程序异常的含义。您可能需要调查它与事务管理逻辑的交互方式,特别是涉及事务回滚时。在我的工作中,我不得不添加@ApplicationException(rollback = false)以禁止事务管理器在抛出异常并向上传播时回滚我的事务。

您可能会告诉我正在使用EJB,但这些概念可能也非常适用于您的设计。

回到你的问题:

  

是否有必要在业务层中记录异常?

如果您打算稍后再登录,则没有必要。您最好在高级别设计日志记录策略,并在那里记录所有捕获的异常。

  

如果没有,我是否需要记录异常(特别是未选中)   的)?

我认为您应该记录异常,因为这有助于您稍后调试任何问题。用户通常不够精明,无法捕获任何可能产生的输出,如果异常传播并在他/她的屏幕上打印而不处理它。

  

使用log4j未记录的未捕获异常会发生什么?   (如果它们仍然在控制台中打印,那么它的目的是什么   log4j的?)

我认为它最终将被Web容器捕获并打印到控制台。如果异常向上传播并到达Web容器异常处理安全网,则您的异常将失控。这通常是糟糕设计的标志。最好是控制您的例外情况。为什么想知道容器如何对未捕获的异常做出反应?这个例外对用户有多大益处?我认为从未被捕获的异常中提供的信息几乎是无用的,因为它们远离错误的来源,它们在调试时变得无关紧要并且难以使用。

答案 1 :(得分:1)

您可以创建自己的异常层次结构来包装它们,以便快速识别它所源自的应用程序架构中的位置。此外,人们可以更进一步提供涵盖用例的主要内容的代码和原因。

当潜在的多个客户端砰地关注相同的用例或碰到瓶颈时,什么日志记录可以帮助您识别事件的顺序。日志记录为您提供了一个跟踪序列,因为请求增加了此查询中的拥塞导致其超时,从而导致其他用户看到另一个异常。

处理应用程序并将其显示给用户是另一个问题。

干杯!

答案 2 :(得分:0)

我们绝对不必处理异常只是为了记录它们。我相信如果我们抛出包含源异常的其他异常作为其原因,或者如果我们实现了一些必须在抛出异常时在当前层中实现的逻辑,那么我们应该捕获异常。

是的,将所有方法声明为throws MyException有点冗长。这就是Spring(您使用的)更喜欢使用未经检查的异常的原因。 BTW这是Java 7中的新功能:您可以忽略异常而不声明该方法会抛出异常。

我认为我们仍然需要检查异常,以便开发向第三方应用程序公开API的库。应用程序层异常应该主要是运行时,并且可以在一个中心位置捕获。

答案 3 :(得分:0)

  

是否有必要在业务层中记录异常?

没有。但更多日志=更好地了解正在发生的事情。换句话说,更多日志=较低的性能。

  

使用log4j未记录的未捕获异常会发生什么?

你失去了他们。记录您可以在需要的地方保存日志的东西,并使用过滤器立即获取实际日志。

答案 4 :(得分:0)

不需要捕获业务异常(只要它未经检查)。您无需处理它们或记录它们。你可以吞下它们。问题是 - 什么是这样的例外?

异常表示应用程序工作流程中存在一些不当行为。如果检查过你,通常可以对此做些什么 - 尝试再做一些操作,做一些解决方法,尝试不同的操作等。

如果未经检查,通常是您不知道如何处理或不能处理的例外情况。

如果您所做的只是捕获异常并记录它,那么它被认为是代码味道。吞咽它不是 不好,但仍然 - 它不好。

需要一些容器(即EJB)来记录发生的异常。此外,在EJB 3.x中,如果您处于JTA托管事务中,并且您不会捕获未标记为@ApplicationException(rollback=false)的未经检查的异常,则事务将自动回滚。这可能就是为什么你只能在里面记录代码就能看到一些try ... catch块的原因。

如果你想在你的业务逻辑中摆脱异常处理代码,你可能会引入一个拦截器,它会对特定的异常做出适当的反应。

HTH!

答案 5 :(得分:0)

首先,您可以并且必须记录所有异常的异常堆栈跟踪。实际上,IMO如果你只记录发生了异常,你可能根本就不记录它。然而,这通常会导致对异常的放松观点。您应该努力的是拥有2个日志文件或一个特定类别,如果该类别中存在例外,则表示发生了重要事件,必须予以解决。即使这意味着多次记录相同的异常。而不是根本没有。

其次,将所有异常更改为已检查的异常是很好的 - 大多数异常都不是“可恢复的”。我做得很好,只是将所有事务包装在异常处理包装器中,记录异常,然后我可以保证记录所有异常。此外,创建一组扩展运行时异常的异常类 - 这比将异常重新抛出为运行时异常要好得多,因为在包装异常时,内部异常堆栈跟踪通常不会完整记录。

第三,重要的是要创建一种机制,将过滤到前端的异常映射到后端原因。这很有挑战性,但这非常重要。如果您可以将它们映射回日志文件中的异常堆栈跟踪,那么用户看到的错误很容易被追踪。