Java 如果过滤器被声明为Springbean,有没有办法告诉Spring不要注册过滤器?

Java 如果过滤器被声明为Springbean,有没有办法告诉Spring不要注册过滤器?,java,spring,spring-mvc,filter,Java,Spring,Spring Mvc,Filter,我正在构建一个应用程序框架,它(作为实现的一部分)使用SpringFilterRegistrationBeanbeans注册过滤器。注册方法(用@Bean注释)根据确定过滤器是打开还是关闭的某些逻辑,返回包装真实过滤器的FilterRegistrationBean,或伪ServletContextInitializer。(这样可以避免停用的过滤器使过滤器链混乱。) 现在,我希望过滤器能够感知上下文。因此,我将过滤器设置为@组件 @Component public class MyRealFilt

我正在构建一个应用程序框架,它(作为实现的一部分)使用Spring
FilterRegistrationBean
beans注册过滤器。注册方法(用
@Bean
注释)根据确定过滤器是打开还是关闭的某些逻辑,返回包装真实过滤器的
FilterRegistrationBean
,或伪
ServletContextInitializer
。(这样可以避免停用的过滤器使过滤器链混乱。)

现在,我希望过滤器能够感知上下文。因此,我将过滤器设置为
@组件

@Component
public class MyRealFilter implements Filter {
    @Autowired
    private ApplicationContext applicationContext;

    // stuff
}
如果过滤器处于打开状态(
someLogic()
以上返回true),并且Spring仍然尊重您在
FilterRegistrationBean
上指定的任何配置,那么这就可以正常工作。但是,如果关闭过滤器,过滤器仍然会被注册,因为它是
@组件
。Spring似乎会自动注册任何声明为
@组件的过滤器,除非该过滤器已经在
FilterRegistrationBean
中注册

有没有办法告诉Spring不要注册声明为
@组件的过滤器?或者我希望过滤器能够感知上下文,但仍然只能通过
FilterRegistrationBean
注册,而不是直接注册,以此来解决这个问题


更新:我后来发现,如果我自己在这样一个
register()
方法中构造bean,那么
@ApplicationContext
实际上不会自动连接。解决这个问题的方法是将
FilterRegistrationBean
的子类声明为具有
@PostConstruct
@Component
,而不是使用
register()

使用
@ConditionalOn
内容来确定需要注册的内容。不要将它放在过滤器或
@Bean
方法上,而是在
@Configuration
类上执行它

@Configuration
public class OptionalWebFiltersConfiguration {

    @Configuration
    @ConditionalForFilterX
    public static class FilterXConfiguration {

        @Bean
        public Filter filterX() {
             return new FilterX();
        }

        @Bean
        public FilterRegistrationBean filterXRegistrationBean() {
             FilterRegistrationBean frb = new FilterRegistrationBean frb = new FilterRegistrationBean(filterX());
             // other config
             return verb;
        }
    }
}

这将仅包括满足条件时的过滤器配置,而不包括复制条件指令。这也是Spring引导如何注册筛选器、侦听器等(例如,请参见如何)。只有在首次初始化Spring上下文时,才应在运行时创建筛选器。为什么不扩展BeanFactoryPostProcessor并评估创建BeanDefinition与否之间的逻辑分支。如果逻辑的计算结果为true,则应在应用程序上下文中创建并注册BeanDefinition。顺便说一句,如果您手动将过滤器标记为@Component,则无需将其注册到spring容器中(这只是将bean注册到spring容器的一种基于注释的方法)。为了避免伪(出于某种原因),您可以创建名为Acceptable的自定义接口,并使用“accept”方法实现它。它应该返回运行时生成的聚合值(实例值)。因此,当您在FilterRegistrationBean中创建过滤器时,无论“someLogic”是什么,都应该创建它,并根据您的逻辑将值“accept”设置为true或false。稍后,后处理器应该获取这个bean,检查它是否应该被应用(通过过滤方法“accept”),如果它返回false(这取决于您如何创建它),后处理器应该使用BeanDefinitionRegistry#removeDefinition(..)从上下文中删除它。有条件地注册筛选器,这就是
@ConditionalOn
内容的用途,您可以使用自己的条件表达式对其进行扩展。这不起作用,因为我无法自动连线。在您的术语中,
FilterX
不能将内容自动连接到其中。这就是为什么我需要使用我在问题评论中描述的混合解决方案。不,你不需要。。。如果它是一个豆子,它会让东西自动连线。。。如果在创建过滤器注册的方法中创建过滤器,它将不起作用,但如果将其创建为bean,它将起作用。关键是您需要将两者注册为
@Bean
,而不是在创建另一个的方法中创建一个。它必须像豆子一样可见。啊,对了,我明白了。这在我的头脑中是有道理的,但我将在下周进行测试。谢谢你的建议!
@Configuration
public class OptionalWebFiltersConfiguration {

    @Configuration
    @ConditionalForFilterX
    public static class FilterXConfiguration {

        @Bean
        public Filter filterX() {
             return new FilterX();
        }

        @Bean
        public FilterRegistrationBean filterXRegistrationBean() {
             FilterRegistrationBean frb = new FilterRegistrationBean frb = new FilterRegistrationBean(filterX());
             // other config
             return verb;
        }
    }
}