【问题标题】:Spring @ComponentScan exclude/include filtersSpring @ComponentScan 排除/包含过滤器
【发布时间】:2026-02-03 11:05:01
【问题描述】:

作为 Spring MVC 应用程序的一个好习惯,Web 配置应该只选择“前端”组件,例如 @Controller@RestController
每个其他 bean 都应该被 Root 应用程序上下文拾取。

我已将 Web 配置定义如下(请记住,我不需要 @EnableMvc 注释,因为它扩展了 WebMvcConfigurationSupport

@Configuration
@ComponentScan(
        basePackages = { ... },
        useDefaultFilters = false,
        includeFilters = @Filter({
                Controller.class,
                ControllerAdvice.class}))

以及Root配置如下。

@Configuration
@ComponentScan(
        basePackages = { ... },
        excludeFilters = @Filter({
                Controller.class,
                ControllerAdvice.class}))

我定义了两个@RestControllerAdvice 类,第一个捕获所有通用Exception(s),第二个捕获更具体的ServiceException

当抛出 ServiceException 时,不会调用特定的顾问,而只会选择通用的顾问。两个配置类中的基本包相同。

我还需要在排除和包含过滤器上指定RestControllerAdvice 吗?还是我错过了什么?

编辑:

@RestControllerAdvice 都没有 basePackeges 或任何特定条件。 而ServiceException 确实找到并注册了。

如果我将异常处理程序移动到工作处理程序而不是调用它。 这就是我让它工作的方式。如果我将 ServiceException 处理程序移动到一个单独的类中,它将不再被调用。

@RestControllerAdvice
public class GlobalRestControllerAdviser extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity<Object> handleBindException(
            final BindException ex,
            final HttpHeaders headers,
            final HttpStatus status,
            final WebRequest request) {
        return new ResponseEntity<Object>(
                buildPresentableError(ex.getAllErrors().get(0)),
                HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(ServiceException.class)
    protected Response<?> handleServiceException(final ServiceException e) {
        ...
    }

    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Object> handleGenericException(final Exception ex) {
        ...
    }
}

似乎最通用的ExceptionHandler 覆盖了更具体的ExceptionHandler

【问题讨论】:

    标签: java spring spring-mvc annotations


    【解决方案1】:

    差不多了,使用FilterType type 并分离过滤器。

    @Configuration
    @ComponentScan(
        basePackages = { ... },
        excludeFilters = {
            @ComponentScan.Filter(type=FilterType.ANNOTATION, value=Controller.class),
            @ComponentScan.Filter(type=FilterType.ANNOTATION, value=ControllerAdvice.class)
        }
    )
    

    或者,我建议您创建一个自定义注释(例如@FrontEnd)并对其应用过滤器。

    【讨论】:

    • 但为什么是 ASSIGNABLE_TYPE?不是正确的FilterType ANNOTATION吗?
    • 然后你可以删除它,因为 ANNOTATION 是它的默认值。我现在要尝试拆分过滤器
    • 对。我总是明确地使用FilterType,因为为了便于阅读,我组合了这些类型。
    • 不,似乎拆分过滤器不起作用。 ControllerAdvice 被拾起,我在日志中看到它。好奇怪
    • 奇怪,它对我有用。您是否尝试过引入自定义注释作为替代方式?
    【解决方案2】:

    基本上@ControllerAdvice 注释类是有序的,这意味着如果 Spring 内部找到一个接受抛出异常的 @ExceptionHandler,它将使用那个并停止。

    当有多个类时,可以使用@Order 设置bean 优先级(例如)。使用 @Order 注释 ServiceException 包含类使其工作。

    此外,基于此功能请求https://jira.spring.io/browse/SPR-8881,我们可以在一个@Filter 注释上指定多个类,无需将它们拆分为多个@Filter(s)。

    【讨论】: