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

Spring WebFlux:RestController获取同名ApplicationContext/MessageResource实例

解决Spring中ApplicationContext实例不一致的问题

这个问题我之前也碰到过!核心原因是你手动通过XML创建的ApplicationContext和Spring MVC/Spring Boot框架自动初始化的根上下文是完全独立的两个实例,它们的Bean容器相互隔离,所以注入的MessageResource自然不是同一个。下面是具体的解决步骤:

1. 停止手动创建ApplicationContext,交给Spring统一管理

首先要移除你手动创建上下文的代码(比如new ClassPathXmlApplicationContext("config.xml")),让Spring框架负责上下文的初始化:

  • 如果是Spring Boot项目:确保你的主启动类上标注了@SpringBootApplication,它会自动扫描项目中的Bean并加载配置。如果需要引入config.xml,可以在主类上添加@ImportResource("classpath:config.xml"):
    @SpringBootApplication
    @ImportResource("classpath:config.xml")
    public class YourApplication {
        public static void main(String[] args) {
            SpringApplication.run(YourApplication.class, args);
        }
    }
    
  • 如果是传统Spring MVC项目:在web.xml中配置ContextLoaderListener,让它加载你的config.xml作为根上下文:
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:config.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    

2. 确保MessageSource在config.xml中正确配置

检查你的config.xml,确保MessageSource的配置正确指向你的greeting.properties文件:

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <!-- basename指向classpath下的messages/greeting,对应messages/greeting.properties -->
    <property name="basename" value="classpath:messages/greeting"/>
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

这里注意basename不要加.properties后缀,Spring会自动识别对应的属性文件。

3. 在RestController中正确注入MessageSource

现在可以放心地在控制器中注入MessageSource,它会和Spring根上下文里的实例保持一致。推荐使用构造器注入(比字段注入更利于测试和依赖明确):

@RestController
public class GreetingController {

    private final MessageSource messageSource;

    // 构造器注入,Spring会自动匹配对应的Bean
    public GreetingController(MessageSource messageSource) {
        this.messageSource = messageSource;
    }

    @GetMapping("/greet")
    public String getGreeting(@RequestHeader(name = "Accept-Language", required = false) Locale locale) {
        // 从properties文件中读取消息
        return messageSource.getMessage("greeting.message", null, locale);
    }
}

如果习惯用字段注入,也可以这样写,但不推荐:

@RestController
public class GreetingController {

    @Autowired
    private MessageSource messageSource;

    // ... 业务代码
}

4. 验证实例一致性

可以在控制器中注入ApplicationContext,打印它的ID来确认和之前手动创建的是否为同一个:

@Autowired
private ApplicationContext applicationContext;

@GetMapping("/context-info")
public String getContextInfo() {
    return "当前ApplicationContext ID: " + applicationContext.getId();
}

访问这个接口后,你会发现这个ID和你之前手动创建的上下文ID不同(因为手动创建的已经被移除了),现在整个应用只有一个Spring上下文,所有Bean都是单例共享的。

关键误区提醒

  • 永远不要在Spring管理的Bean(比如控制器、服务类)中手动创建新的ApplicationContext实例,这会导致多个上下文并存,Bean无法共享,还会浪费资源。
  • 确保所有配置文件都被Spring的根上下文加载,避免出现多个上下文的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:28:08