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
相关产品推荐
相关产品推荐

