当 Spring 找到两个同名的 bean 时会做什么?
What Spring does when it finds two beans with same name?
我们有一个基于 Spring 4.0.5.RELEASE 的应用程序,我们错误地引入了两个同名的 bean。这两个 bean 都是 RestTemplate 版本 4.2.2 的实例,Spring 进行 HTTP 调用的框架:
第一个"restTemplate"豆
@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(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 定义:替换[根 bean: class [null];范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; factoryBeanName=配置通用; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.common.config.ConfigCommon] 中使用 [Root bean: class [null] 定义;范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; 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 定义:替换[根 bean: class [null];范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; factoryBeanName=configCentralReservations; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.centralreservations.config.ConfigCentralReservations] 中使用 [Root bean: class [null] 定义;范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; factoryBeanName=配置通用; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 定义于com.service.common.config.ConfigCommon]
我能想到很多原因:
- 类路径扫描returnsconfig-annotated类以未指定的顺序,
- 配置类存储在没有指定顺序的HashMap中,
Class.getMethods()
返回的方法以未指定的顺序返回,
- 等等等
您应该问自己:为什么要使用一个而不是另一个?您是否在任何地方指定了订单? Spring 在这方面提供任何保证吗?如果没有,你不应该假设任何事情。
我们有一个基于 Spring 4.0.5.RELEASE 的应用程序,我们错误地引入了两个同名的 bean。这两个 bean 都是 RestTemplate 版本 4.2.2 的实例,Spring 进行 HTTP 调用的框架:
第一个"restTemplate"豆
@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(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 定义:替换[根 bean: class [null];范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; factoryBeanName=配置通用; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.common.config.ConfigCommon] 中使用 [Root bean: class [null] 定义;范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; 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 定义:替换[根 bean: class [null];范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; factoryBeanName=configCentralReservations; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 在 com.service.centralreservations.config.ConfigCentralReservations] 中使用 [Root bean: class [null] 定义;范围=;摘要=假;懒惰初始化=假;自动接线模式=3;依赖检查=0; autowireCandidate=真;初级=假; factoryBeanName=配置通用; factoryMethodName=restTemplate;初始化方法名=空; destroyMethodName=(推断); 定义于com.service.common.config.ConfigCommon]
我能想到很多原因:
- 类路径扫描returnsconfig-annotated类以未指定的顺序,
- 配置类存储在没有指定顺序的HashMap中,
Class.getMethods()
返回的方法以未指定的顺序返回,- 等等等
您应该问自己:为什么要使用一个而不是另一个?您是否在任何地方指定了订单? Spring 在这方面提供任何保证吗?如果没有,你不应该假设任何事情。