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

Java 9模块化项目集成Spring Security时ResourceBundle.Control异常问题

解决Java 9模块化+Spring Boot 2.0集成Spring Security的ResourceBundle.Control异常

这个坑我之前帮好几个开发者踩过,本质就是Java 9的模块化系统对ResourceBundle.Control的限制,撞上了Spring Security默认的资源加载逻辑。Java 9的命名模块里明确禁止使用自定义的ResourceBundle.Control实现,而Spring Security处理国际化资源时刚好默认用到了它,这就直接抛出UnsupportedOperationException了——不管你是自定义MessageSource还是用默认配置,只要触发了Spring Security的资源加载,就会踩这个坑。

下面给几个亲测有效的解决方案,按推荐优先级排序:

1. 调整模块描述符(module-info.java)

这是最根本的适配方案,让Spring模块能合法访问你的资源:

  • 在module-info.java里,把你存放国际化资源(比如messages.properties)的包开放给Spring Security和Spring Context模块,同时声明依赖:
    // 替换成你实际的资源包路径
    opens com.yourproject.i18n to org.springframework.security.core, org.springframework.context;
    
    requires org.springframework.security.core;
    requires org.springframework.boot.autoconfigure;
    requires org.springframework.context;
    
    这样Spring就能用模块化兼容的方式加载资源,不会再触发ResourceBundle.Control的限制。

2. 换用ReloadableResourceBundleMessageSource绕过限制

Spring的ResourceBundleMessageSource底层依赖ResourceBundle.Control,而ReloadableResourceBundleMessageSource是用自己的资源加载逻辑,完全避开了这个问题。直接自定义这个Bean就行:

@Configuration
public class MessageSourceConfig {

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        // 指向你的资源文件,比如classpath下的messages.properties
        messageSource.setBasename("classpath:messages");
        messageSource.setDefaultEncoding("UTF-8");
        // 可选:设置缓存时间,方便开发时热更新
        messageSource.setCacheSeconds(3600);
        return messageSource;
    }

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.ENGLISH);
        return localeResolver;
    }
}

然后在Spring Security的配置里,确保异常处理器等组件使用这个自定义的MessageSource:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final MessageSource messageSource;

    public SecurityConfig(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .and()
            .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler())
                .authenticationEntryPoint(authenticationEntryPoint());
    }

    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        SimpleAccessDeniedHandler handler = new SimpleAccessDeniedHandler();
        handler.setMessageSource(messageSource);
        return handler;
    }

    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        LoginUrlAuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint("/login");
        entryPoint.setMessageSource(messageSource);
        return entryPoint;
    }
}

3. 临时降级Spring Security版本(不推荐长期用)

如果上面的方法暂时没法落地,可以试试把Spring Security降到5.0.x系列(对应Spring Boot 2.0的兼容版本)。早期版本的Spring Security对Java 9模块化的兼容性处理没那么严格,可能会绕过这个异常。不过这只是权宜之计,长远来看还是要适配模块化规范。

最后提醒一句:Java 9模块化下,资源文件默认只能从模块路径加载,所以要确保你的messages.properties放在src/main/resources对应的模块包下,或者通过module-info.java的opens/exports声明资源所在的包,不然Spring还是找不到资源。

内容的提问来源于stack exchange,提问作者Grzegorz B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:34:10