【问题标题】:Interceptors Java and checked exception拦截器 Java 和检查的异常
【发布时间】:2014-06-25 06:30:45
【问题描述】:

我正在使用 Spring 的 AOP 功能。 我有一堂课叫

class UserService {
    public User insertUserService(User user) throws PersistenceLayerException {
        System.out.println("UserServiceImpl_Two called: insertUserService method");

        if (user.id == 1) 
            throw new PersistenceLayerException();

        return null;
    }
}

现在,对该方法insertUserService 的调用被拦截器拦截,该拦截器进行一些验证。这个验证拦截器抛出一个名为BusinessException 的检查异常。现在,当抛出这个异常时,Java 会抛出一个UndeclaredThrowableException,因为BusinessExcepetion 没有在insertUserService 的抛出中声明。有没有办法绕过这个UndeclaredThrowableException 而不必在 throws 子句中声明BusinessException。

insertUserService 本身没有抛出 BusinessException 的原因,所以它看起来应该有办法解决。

【问题讨论】:

    标签: java spring interceptor checked-exceptions


    【解决方案1】:

    如果可行的话,一个想法是让BusinessException 成为RuntimeException 的子类,无论如何这更符合Spring 哲学。

    编辑:

    您还询问是否有办法通过检查异常来执行此操作。您可能采取的一种方法是基于重新考虑您的UserService 合同。 “服务”(在服务 bean 意义上)通常是更高级别的域概念,因此无论如何从您的 UserService 合同中声明 BusinessException 可能实际上更合适。然后,当存在较低级别的持久性问题时,您可以使用 BusinessException 包装它(如果 BusinessException 表示“对业务服务的调用失败”之类的通用内容),或者只声明 BusinessException 和 @ 987654330@ 如果您希望 BusinessException 具有狭义(例如验证问题等)。

    在这种情况下,您可能会使用 UserService 作为 Spring Security UserDetailsService,它确实更面向持久性。如果是这样,那么上述想法可能不适用。但除此之外,请考虑这是一个选项。

    说了这么多,将BusinessException 设置为RuntimeException 是最符合Spring 实践的,并且可以说是最佳实践,因为我描述了here。

    【讨论】:

    • 同意。拥有一个抛出检查异常的拦截器可能不是一个好主意。有点违背透明度的想法。
    • @Willie:嘿,我确实在读你的博客 Willie。我同意让它成为 Runtime Exception 的子类是一种方法,但是有什么方法可以处理检查的异常吗?
    • 小世界。 :-) 如果有,我不知道。但我不是 AOP 专家,所以不要把我对这件事的无知当回事。 :-D
    • 谢谢威利。我决定声明两个例外:BusinessException 和 Persistence Exception。我不能让业务异常成为 RuntimeException 的子类,因为它在应用程序的其他地方使用,我不想更改核心异常。
    【解决方案2】:

    我能想到的一种方法(因为您说 BusinessException 是已检查异常),将您的异常与实际抛出的异常一起包装。如下所示,并在您的调用者中适当地处理它。无论如何,不​​建议在 PersistenceException 下包装业务异常(感谢 Wille 指出)

    throw new PersistenceLayerException(new BusinessException(..));
    

    【讨论】:

    • -1 由于此验证发生在 持久层之上。因此,将其包装在 PersistenceLayerException 中会产生误导。
    • 那么首先抛出任何 BusinessException 是不可取的。答案是基于他需要在持久层中进行业务验证的假设。
    • 您仍然可以抛出 BusinessException,然后让一些全局处理程序处理它(例如 @ControllerAdvice),报告无效对象。 PersistenceLayerException 应该表示来自持久层的问题。您所描述的实际上只是通过声明的异常隧道验证请求。
    • 嗯,再想想你的最后一句话,我明白你的意思了。这不是我会这样做的方式,但我会删除反对票,因为我可以看到你的逻辑。
    【解决方案3】:

    我不熟悉 Spring 拦截器,但我相信它背后的逻辑与标准 Java EE javax.interceptor.AroundInvoke 非常相似:

    定义一个插入业务方法的拦截器方法...AroundInvoke 方法可以抛出任何异常它们所插入的方法的 throws 子句允许。

    所以它说你不应该抛出一个未由你用拦截器装饰的业务方法声明的检查异常。

    实际上,不结合检查异常和 AOP 是一种很常见的做法。我将使用 AOP 的异常处理视为使用检查异常的一种替代范例。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 2015-11-22
      • 2016-11-15
      • 1970-01-01
      相关资源
      最近更新 更多