You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复现Spring Security相关的Bean加载顺序异常问题?

问题:Spring Security过滤器与自定义MvcFilter同时加载的异常场景

背景说明

我们为Spring Boot项目开发了一款内部库,包含两个过滤器:

  • SpringMvcFilter:默认加载,通过@ConditionalOnMissingBean(name = "springSecurityFilterChain")控制,当Spring Security的过滤器链不存在时生效
  • SpringSecurityFilter:配置Spring Security时加载,通过AbstractHttpConfigurer将其添加到Security过滤链中

SpringMvcFilter的自动配置代码:

@AutoConfiguration
public class SpringMvcConfig {

    @Bean
    @ConditionalOnMissingBean(name = {"springSecurityFilterChain"})
    public Filter springMvcFilter() {
        // implementation
    }
}

SpringSecurityFilter的配置代码:

public class SpringSecurityConfigurer extends AbstractHttpConfigurer<SpringSecurityConfigurer, HttpSecurity> {

    @Override
    public void configure(HttpSecurity builder) {
        builder.addFilterBefore(new SpringSecurityFilter(), BasicAuthenticationFilter.class);
    }
}

问题现象

正常逻辑下,当客户配置Spring Security时,springSecurityFilterChain Bean存在,SpringMvcFilter应该被@ConditionalOnMissingBean阻止加载。但有一位客户反馈两个过滤器均被加载并生效,本地环境无法复现该问题。

本地复现测试(基于Spring Boot 2.7.16)

为排查问题,搭建了测试项目并引入一个包含三个条件Bean的依赖库:

测试依赖库的自动配置类

@AutoConfiguration
public class CoolReuseBeans {

    @Bean("coolReuseIntBean")
    @ConditionalOnMissingBean(name = {"springSecurityFilterChain"})
    public Integer beanInt() {
        return 5;
    }

    @Bean("coolReuseStringBean")
    @ConditionalOnBean(name = {"springSecurityFilterChain"})
    public String beanString() {
        return "5";
    }

    @Bean("coolReuseBooleanBean")
    public Boolean beanBoolean() {
        return true;
    }
}

项目中的Spring Security配置

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(requests -> requests
                        .requestMatchers(new AntPathRequestMatcher("/")).permitAll()
                        .anyRequest().authenticated());
        return http.build();
    }
}

启动类(用于打印Bean加载情况)

@SpringBootApplication
public class Application {
    private static ConfigurableApplicationContext applicationContext;

    public static void main(String[] args) {
         applicationContext = SpringApplication.run(Application.class, args);
        hasBean("springSecurityFilterChain");
        hasBean("coolReuseIntBean");
        hasBean("coolReuseStringBean");
        hasBean("coolReuseBooleanBean");
    }

    private static void hasBean(String name) {
        String[] allBeanNames = applicationContext.getBeanDefinitionNames();
        System.out.println(String.format("Did find %s? %s", name, Arrays.stream(allBeanNames).anyMatch(x -> x.equals(name))));
    }
}

测试结果1:开启@EnableWebSecurity

日志输出:

253: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'springSecurityFilterChain'

366: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'com.example.beans.CoolReuseBeans'
367: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseStringBean'
368: DEBUG 36231 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseBooleanBean'

CoolReuseBeans#beanString matched:
      - @ConditionalOnBean (names: springSecurityFilterChain; SearchStrategy: all) found bean 'springSecurityFilterChain' (OnBeanCondition)

CoolReuseBeans#beanInt:
      Did not match:
         - @ConditionalOnMissingBean (names: springSecurityFilterChain; SearchStrategy: all) found beans named springSecurityFilterChain (OnBeanCondition)


Did find springSecurityFilterChain? true
Did find coolReuseIntBean? false
Did find coolReuseStringBean? true
Did find coolReuseBooleanBean? true

结果符合预期:springSecurityFilterChain先加载,coolReuseIntBean因条件不满足未被创建。

测试结果2:注释@EnableWebSecurity

日志输出:

366: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'com.example.beans.CoolReuseBeans'
367: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseIntBean'
368: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'coolReuseBooleanBean'

385: DEBUG 37070 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Creating shared instance of singleton bean 'springSecurityFilterChain'

CoolReuseBeans#beanInt matched:
      - @ConditionalOnMissingBean (names: springSecurityFilterChain; SearchStrategy: all) did not find any beans (OnBeanCondition)

CoolReuseBeans#beanString:
      Did not match:
         - @ConditionalOnBean (names: springSecurityFilterChain; SearchStrategy: all) did not find any beans named springSecurityFilterChain (OnBeanCondition)

Did find springSecurityFilterChain? true
Did find coolReuseIntBean? true
Did find coolReuseStringBean? false
Did find coolReuseBooleanBean? true

这里出现异常现象:即使未配置Spring Security,springSecurityFilterChain仍会被加载,只是加载顺序晚于CoolReuseBeans的Bean。

疑惑与求助

唯一能解释客户问题的场景是:springSecurityFilterChain在包含SpringMvcFilter的@AutoConfiguration之后加载,导致@ConditionalOnMissingBean条件满足,SpringMvcFilter被创建;之后springSecurityFilterChain才被加载,最终两个过滤器共存。但本地无法复现这个加载顺序,而且按认知@AutoConfiguration应该在Bean加载的最后阶段处理,不该出现这种顺序问题。

求问有没有人知道该问题的原因,或者能提供复现方法?

内容的提问来源于stack exchange,提问作者Dennis H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:34:54