【问题标题】:@ControllerAdvice Not Firing@ControllerAdvice 未触发
【发布时间】:2014-02-19 15:18:27
【问题描述】:

我正在开发一个 Spring MVC/Webflow 应用程序(版本 3.2),并试图让异常处理工作,我可以将自定义异常消息输出到日志文件和 error.jsp。我遇到的问题是异常处理程序没有被解雇。我创建了以下类并将其注释为“@ControllerAdvice”并将其放入与引发异常的控制器相同的包中:

@ControllerAdvice
public class MyCustomExceptionController {

    @ExceptionHandler(MyCustomException.class)
    public ModelAndView handleMyException(MyCustomException ex) {   
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("/error/error");
        modelAndView.addObject("errorId", ex.getErrorId());
        modelAndView.addObject("message", ex.getErrorMessage());        
        return modelAndView;
    }
}

并将以下内容添加到 mvc-config 文件中:

<mvc:annotation-driven/>

并在我的 app-config 文件中包含以下内容:

<context:component-scan base-package="package containing my controllers and MyCustomExceptionController">
        <context:include-filter type="annotation" 
    expression="org.springframework.web.bind.annotation.ControllerAdvice" />
    </context:component-scan> 

任何想法为什么这不起作用?

【问题讨论】:

  • 方法handleMyException() 只会在您选择的未处理的自定义异常发生时调用 (MyCustomException)。即使在抛出MyCustomException 之后,这个方法是否被调用? This 是您可能会更接近的教程。
  • 我在 handleMyException 上放了一个断点,即使我抛出 MyCustomException,该方法也永远不会被调用。
  • 如果您要在此类中使用@InitBinder 注释来注释您选择的方法,例如,该方法是否被调用?
  • 嗨 Tiny,我在同一个类中添加了以下测试方法,但它从未被调用:@InitBinder public void InitBinder() { System.out.println("In InitBinder method"); }
  • 我有this 配置文件(dispatcher-servlet.xml)。您想将它与您的配置文件进行比较吗?除此之外,我在另一个文件applicationContext.xml 中指定了&lt;context:annotation-config/&gt;,但这应该与您面临的具体问题无关。 @ControllerAdvice 注释在 Spring 3.2.2 和 Spring 4.0.0 GA 中都适用于这些配置(免责声明:我不了解 Spring WebFlow)。

标签: java spring spring-mvc exception-handling


【解决方案1】:

&lt;mvc:annotation-driven/&gt; 元素隐式注册了一个ExceptionHandlerExceptionResolver bean。这个类有一个initExceptionHandlerAdviceCache() 方法,它扫描上下文中的bean 以查找其类类型用@ControllerAdvice 注释的那些。

它首先调用ControllerAdviceBean.findAnnotatedBeans(ApplicationContext)。在内部,此方法使用ApplicationContext#getBeanDefinitionNames()。该方法的javadoc说明

不考虑该工厂可能参与的任何层次结构

澄清这意味着什么。当您在部署描述符中声明ContextLoaderListener 时,它会加载我们称为根或应用程序ApplicationContext 并使其在ServletContext 中可用。然后,当您声明 DispatcherServlet 时,它会创建自己的 servlet ApplicationContext 并使用它在 ContextLoaderListener 加载的 ServletContext 属性中找到的任何 ApplicationContext 作为该上下文的父级.层次结构是这样的

Root ApplicationContext // loaded by the ContextLoaderListener
            |
Servlet ApplicationContext // loaded by the DispatcherServlet

每个ApplicationContext 都可以访问父上下文中的bean,但反之则不行。

上面的方法选择不使用父上下文中的bean,因此只能访问当前ApplicationContext(实际上是BeanFactory)中的bean。

因此,如果您的

<context:component-scan .../>

在根 ApplicationContext 中声明,正如我从名称 app-config 中假设的那样,但

<mvc:annotation-driven />

在 servlet ApplicationContext 中声明,再次假设从 mvc-config,然后寻找 @ControllerAdvice bean 的 ExceptionHandlerExceptionResolver 将找不到任何。它正在 servlet 上下文中寻找 bean,但它们不存在,它们在根上下文中。

【讨论】:

  • 那么我们应该在这里做什么?
  • @gabby 你把上面提到的配置元素重新排列在一起。
  • 很好的解释,但仍然缺少解决方案
  • 根据答案,解决方案很简单——我刚刚将 从 mvc-config 移到了 app-config,一切都开始工作了
【解决方案2】:

万一其他人遇到这样的问题 - 我发现了一个错误。

我只有一个 RequestMapping (http://localhost:8080/myapp/verify/verify)

InterceptorController 的 PreHandle 方法中,我明确地抛出了一个异常 -> throw new MyCustomException("error","error.jsp") 来测试我的 @ControllerAdvice Exception 处理。

当我转到 http://localhost:8080/myapp/ 时,我会看到拦截器控制器被调用,我的自定义异常被抛出,但我的 @ExceptionHandler(MyCustomException.class)@ControllerAdvice 类从未被调用。

我添加了@RequestMapping(value="/"),它解决了我的问题。由于我试图访问一个没有与之关联的 @RequestMapping 的 URI,因此我得到了一个 'NoHandlerFoundException',它缩短了我的 Exception 冒泡。

简而言之,确保您尝试调用的 URI 具有与之关联的 @RequestMapping,或者在您的 ExceptionHandler 类中有一个方法来处理 NoHandlerFoundException

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2018-08-20
    • 2021-03-14
    • 1970-01-01
    • 2016-03-25
    • 1970-01-01
    • 2023-03-30
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多