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

Spring 5迁移至Spring 6后WebMvc Controller方法陷入无限循环

Spring 6迁移后WebMvc控制器方法无限调用问题

问题背景

从Spring 5迁移至Spring 6后,出现WebMvc控制器方法被无限调用的异常,相同配置在Spring 5环境下可正常运行。相关配置代码如下:

SecurityWebApplicationInitializer.java

public class SecurityWebApplicationInitializer 
  extends AbstractSecurityWebApplicationInitializer {

}

WebMvcApplicationInitializer.java

public class MvcWebApplicationInitializer extends
  AbstractAnnotationConfigDispatcherServletInitializer {

@Override
protected Class<?>[] getServletConfigClasses() {
    return new Class[] { SecurityConfig.class, WebMvcConfig.class 
  };
}

@Override
protected Class<?>[] getRootConfigClasses() {
    return null;
}

@Override
protected String[] getServletMappings() {
    return new String[] { "/" };
}

}

WebMvcConfig.java

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {
 "com.feedbager"
})
public class WebMvcConfig implements WebMvcConfigurer {

@Bean
public InternalResourceViewResolver resolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setViewClass(JstlView.class);
    resolver.setPrefix("/WEB-INF/jsp/");
    resolver.setSuffix(".jsp");
    return resolver;
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
        .addResourceHandler("/resources/**")
        .addResourceLocations("/resources/");
}
 
}

SecurityConfig.java

@Configuration
@EnableWebSecurity
@ComponentScan("com.feedbager")
public class SecurityConfig {

@Bean
public AuthenticationManager authenticationManager(HttpSecurity http) 
  throws Exception {
    AuthenticationManagerBuilder authenticationManagerBuilder = 
            http.getSharedObject(AuthenticationManagerBuilder.class);
        authenticationManagerBuilder.authenticationProvider(authenticationProvider);
        return authenticationManagerBuilder.build();
}

@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
    return web -> web.ignoring()
            .requestMatchers("/resources/**");
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf(AbstractHttpConfigurer::disable)
      .authorizeHttpRequests(authorizationManagerRequestMatcherRegistry ->
              authorizationManagerRequestMatcherRegistry
                .requestMatchers("/shop/**").hasAnyAuthority("ROLE_SHOP")
                .requestMatchers("/user/**").hasAnyAuthority("ROLE_USER")
                .requestMatchers("/manufacturer/**").hasAnyAuthority("ROLE_MANUFACTURER")
                .requestMatchers("/register").permitAll()
                .requestMatchers("/index").permitAll()
                .requestMatchers("/accessDenied").permitAll()
                .requestMatchers("/verify").permitAll()
                .requestMatchers("/shops").permitAll()
                .requestMatchers("/manufacturers").permitAll()
                .requestMatchers("/articles").permitAll()
                .anyRequest().authenticated())
                .formLogin(form -> form
                    .successHandler(loginSuccessHandler).loginProcessingUrl("/process-login").loginPage("/index").failureUrl("/index?error")
                    .permitAll()
                )
                .httpBasic(Customizer.withDefaults())
                .sessionManagement(httpSecuritySessionManagementConfigurer -> httpSecuritySessionManagementConfigurer
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS));

    return http.build();
}

@Bean
public PasswordEncoder passwordEncoder(){
    PasswordEncoder encoder = new BCryptPasswordEncoder();
    return encoder;
}

@Autowired
private AuthenticationProvider authenticationProvider;

@Autowired
private LoginSuccessHandler loginSuccessHandler;
}

疑问:Spring 6在控制器返回逻辑方面是否有新变化?如何让控制器方法仅被调用一次?


问题分析与解决方案

核心原因

你的问题并非Spring 6控制器返回逻辑的直接变更导致,而是重复组件扫描与无状态会话配置冲突在Spring 6更严格的Bean生命周期管理下暴露的问题:

  1. 重复Bean实例化
    WebMvcConfig和SecurityConfig都配置了@ComponentScan("com.feedbager"),且两者均被注册到Servlet上下文(getServletConfigClasses返回这两个配置类)。这会导致控制器、处理器等Bean被重复创建,请求分发时出现循环调用。Spring 5对重复Bean的处理更宽松,未触发该问题,但Spring 6严格了Bean的唯一性校验与生命周期管理。

  2. 无状态会话与表单登录的矛盾
    你在Security配置中设置了SessionCreationPolicy.STATELESS,但表单登录依赖会话存储认证状态。无状态配置会导致每次请求都需要重新认证,进而触发控制器方法的重复调用。

修复步骤

  • 拆分组件扫描范围
    移除SecurityConfig上的@ComponentScan("com.feedbager"),仅保留WebMvcConfig的组件扫描,或对两者的扫描范围做细分(比如com.feedbager.controller给WebMvc,com.feedbager.security给Security),避免Bean重复创建:

    @Configuration
    @EnableWebSecurity
    // 移除@ComponentScan("com.feedbager")
    public class SecurityConfig {
        // 原有代码保持不变
    }
    
  • 调整会话策略
    表单登录依赖会话维护认证状态,需将会话策略改为默认的SessionCreationPolicy.IF_REQUIRED:

    .sessionManagement(httpSecuritySessionManagementConfigurer -> 
        httpSecuritySessionManagementConfigurer
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
    )
    
  • 优化上下文配置
    将Security配置移至根上下文,WebMvc配置保留在Servlet上下文,避免上下文混淆:

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { SecurityConfig.class };
    }
    
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { WebMvcConfig.class };
    }
    

关于Spring 6控制器返回逻辑的变化

Spring 6在控制器返回逻辑上的主要变更集中在:

  • 默认使用PathPatternParser替代AntPathMatcher(可通过配置切换回旧模式)
  • 响应式控制器的行为优化
  • 对@ResponseBody和视图返回的类型推断更严格

但这些变化与你的无限调用问题无关,无需针对返回逻辑做额外调整。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:33:09