【发布时间】:2015-12-29 21:28:03
【问题描述】:
我们有一个基于 Spring 4.0.5.RELEASE 的应用程序,我们错误地引入了两个同名的 bean。这两个 bean 都是 RestTemplate 版本 4.2.2 的实例,这是用于进行 HTTP 调用的 Spring 框架:
第一个“restTemplate”bean
@Bean(name = "restTemplate")
protected RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new RestTemplateErrorHandler());
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
MappingJackson2HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
// Disable exceptions on unknown incoming properties
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jacksonConverter.setObjectMapper(mapper);
messageConverters.add(jacksonConverter);
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
第二个“restTemplate”bean,完全原始
@Bean(name = "restTemplate")
protected RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
return restTemplate;
}
两者的主要区别在于错误处理。这就是问题所在:
我们有四台服务器正在运行,我们在每台服务器中部署了相同的 war 文件。根据日志,我们 100% 确定在前两台服务器中,正在使用带有错误处理的 restTemplate 实例。而在另外两个中,没有使用没有错误处理的实例。
为什么 Spring 会这样?它以完全不确定的方式注入“restTemplate”bean。这种行为的原因可能是什么?我希望在所有 4 台服务器中都有相同的“restTemplate”实例。
我把日志放在这里,显示我要解释的内容。看看大胆的声明!
服务器一:
[timestamp=19:09:23.846] [thread="localhost-startStop-1"] [session="undefined"] [request="undefined"] [level=INFO ] [logger=o.s.b.f.s.DefaultListableBeanFactory] [class=org.springframework.beans.factory.support.DefaultListableBeanFactory] [line=839] - 用不同的定义覆盖 bean 'restTemplate' 的 bean 定义:替换 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真;主要=假; factoryBeanName=configCommon; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.common.config.ConfigCommon 中定义] 与 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真;主要=假; factoryBeanName=configCentralReservations; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.centralreservations.config.ConfigCentralReservations 中定义]
服务器二:
[timestamp=19:04:41.717] [thread="localhost-startStop-1"] [session="undefined"] [request="undefined"] [level=INFO ] [logger=o.s.b.f.s.DefaultListableBeanFactory] [class=org.springframework.beans.factory.support.DefaultListableBeanFactory] [line=839] - 用不同的定义覆盖 bean 'restTemplate' 的 bean 定义:替换 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真;主要=假; factoryBeanName=configCentralReservations; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.centralreservations.config.ConfigCentralReservations 中定义] 与 [Root bean: class [null];范围=;摘要=假;懒惰初始化=假;自动线模式=3;依赖检查=0;自动接线候选=真;主要=假; factoryBeanName=configCommon; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.common.config.ConfigCommon 中定义]
【问题讨论】:
-
谢谢,这帮助我们再次确认,出于某种原因,Spring 在某些服务器中为 B 覆盖了 A,而在其他服务器中为 A 覆盖了 B。
-
@Kayaman 无缘无故关闭了这个问题,因为他提供的链接没有回答我的问题。我将编辑我的问题,所以请 Kayaman 在再次关闭之前尝试了解问题。我知道 Spring 会覆盖具有相同名称的 bean。问题是它的行为不是确定性的。相同的战争文件,部署在 4 个不同的服务器中,在前两个服务器中,B 覆盖 A,在后两个服务器中,B 覆盖 A。有问题吗?请告诉我。
-
@Kayaman,我刚刚编辑,你能重新打开它吗?谢谢!
-
我可以想象很多原因:类路径扫描以未指定的顺序返回配置注释的类,配置类存储在没有指定顺序的 HashMap 中,Class.getMethods() 返回的方法返回一个未指定的订单,等等等等。你应该问自己:为什么要使用一个而不是另一个?您是否在任何地方指定了订单? Spring 在这方面是否提供任何保证?如果不是,你不应该假设任何事情。