【问题标题】:Better understanding exceptions and logging in a J2EE environment更好地理解 J2EE 环境中的异常和日志记录
【发布时间】:2011-11-04 20:01:17
【问题描述】:

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

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

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

问题:

  1. 是否需要在业务层记录异常?如果没有,做 我需要记录异常(尤其是未检查的异常)吗?
  2. 未使用 log4j 记录的未捕获异常会发生什么情况? (如果它们仍然打印在控制台中,那么目的是什么? log4j?)

我对这个过程的工作原理感到困惑......

谢谢。

编辑:如果在外部库(Spring、Hibernate 等)中发生异常,是否假定这些异常将使用正在使用的任何日志记录机制打印出来?在那种情况下,我想我只需要记录我的代码抛出的异常......还是我在这里离基地很远?

【问题讨论】:

    标签: java jakarta-ee log4j


    【解决方案1】:

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

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

    1. 如果您无法处理异常,请不要捕获它。
    2. 如果您发现异常,请不要吞下它。
    3. 在尽可能接近其源的位置捕获异常。
    4. 在您捕获的地方记录一个异常,除非您打算重新抛出它。
    5. 根据异常处理的细粒度来构建方法。
    6. 根据需要使用尽可能多的类型化异常,尤其是应用程序异常。

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

    IBM DeveloperWorks: EJB best practices

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

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

    您也许可以看出我正在使用 EJB,但这些概念可能也非常适用于您的设计。

    回到你的问题:

    是否需要在业务层记录异常?

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

    如果不需要,我是否需要记录异常(尤其是未经检查的 那些)?

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

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

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

    【讨论】:

      【解决方案2】:

      您可以创建自己的异常层次结构来包装它们,以便快速识别它源自应用程序架构中的哪个位置。还可以进一步提供涵盖大多数用例的代码和原因。

      当可能有多个客户端猛烈抨击同一个用例或遇到瓶颈时,日志记录可以帮助您识别事件的顺序。日志记录为您提供了一个追溯序列,因为请求增加,此查询中存在拥塞导致它超时,因此其他用户看到另一个异常。

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

      干杯!

      【讨论】:

        【解决方案3】:

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

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

        我相信我们仍然需要检查异常来开发将 API 暴露给 3rd 方应用程序的库。应用层异常应该主要是运行时的并且在一个中心位置被捕获。

        【讨论】:

          【解决方案4】:

          是否需要在业务层记录异常?

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

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

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

          【讨论】:

            【解决方案5】:

            不需要捕获业务异常(只要它未被选中)。您不需要处理它们或记录它们。你可以把它们吞下去。问题是——这样的例外是为了什么?

            异常表明您的应用程序工作流程中有一些不当行为。如果它被检查过,你通常可以做点什么——尝试再做一些操作,做一些变通方法,尝试不同的操作,等等。

            如果未选中,则通常是您不知道或无法处理的异常。

            如果您所做的只是捕获异常并将其记录下来,则会被视为代码异味。它不像吞下它那么糟糕,但仍然 - 它不好。

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

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

            HTH!

            【讨论】:

              【解决方案6】:

              首先,您可以而且必须记录所有异常的异常堆栈跟踪。事实上,IMO 如果您只记录发生的异常,您可能根本不记录它。然而,这通常会导致对异常的放松看法。您应该争取的是拥有 2 个日志文件或一个特定类别,如果异常属于该类别,则意味着发生了严重的事情并且必须解决。即使这意味着多次记录相同的异常。太多了而不是根本没有。

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-11-10
                • 1970-01-01
                • 2020-12-31
                • 2011-07-08
                • 1970-01-01
                • 2012-02-10
                • 1970-01-01
                相关资源
                最近更新 更多