在Config文件中用@Bean注解装配bean的一个问题
Spring中配置与使用bean的一些方法参见https://www.jianshu.com/p/f3eaa90fb51e
*******************正文分割线*******************
我们通常会在@Configuration
注解的的类中使用@Bean
注解来生成让Spring管理的JavaBean,例如:
@Configuration
public class Test {
@Bean
public UsedBean createBean() {
return new UsedBean();
}
}
public class UsedBean {
// 省略
}
这样在其他地方就可以导入使用。
@Autowired
private UsedBean usedBean;
现在因为特殊原因,需要在项目中引入两个设置不同的RestTemplate
@Configuration
public class HttpConfig {
/**
* 使用到的HttpClientUtil.createHttpClient()、httpRequestFactory详见文末代码链接,对于理解本文不重要
*/
@Bean(name = "restTemplateA")
public RestTemplate createRestTemplate() {
return new RestTemplate(HttpClientUtil.createHttpClient());
}
@Bean(name = "restTemplateB")
public RestTemplate createRestTemplate(SimpleClientHttpRequestFactory httpRequestFactory) {
return new RestTemplate(httpRequestFactory);
}
}
我们想通过不同的name让Spring区分并管理这两个JavaBean,然后在其他地方通过
@Resource(name = "restTemplateA")
private RestTemplate restTemplateNew;
@Resource(name = "restTemplateB")
private RestTemplate restTemplateOld;
来使用。但是使用过程中发现引入的restTemplateNew和restTemplateOld都是restTemplateB的实例,说明restTemplateA在Config文件中加入Spring的时候,被后加入的restTemplateB覆盖掉了。
一些想法:
- 难道@Bean和@Resource的name因为什么原因没起作用?换了@Autowired和@Qualifier试了一下,还是不行;
- 因为都是RestTemplate类的bean,产生了覆盖?但是spring是不禁止创建同一个类的多个实例的,加上@Scope("propotype")试了一下,果然不行;又分别继承RestTemplate创建了两个不同的类RestTemplateNew和RestTemplateOld,果然也是不行。
后来偶然发现原因是restTemplateA和restTemplateB使用了同样的方法名createRestTemplate导致的这个问题,因为方法的参数不同,所以编译器不会报错。换了不同的名字createRestTemplateA和createRestTemplateB,就正常了,如下所示:
/**
* 使用到的HttpClientUtil.createHttpClient()、httpRequestFactory详见文末代码链接,对于理解本文不重要
*/
@Configuration
public class HttpConfig {
@Bean(name = "restTemplateA")
public RestTemplate createRestTemplateA() {
// 详见文末github代码
return new RestTemplate(HttpClientUtil.createHttpClient());
}
@Bean(name = "restTemplateB")
public RestTemplate createRestTemplateB(SimpleClientHttpRequestFactory httpRequestFactory) {
// httpRequestFactory详见文末github代码
return new RestTemplate(httpRequestFactory);
}
}
出错的地方找到了,那么原因呢?
难道Spring生成Bean的时候根据相同的方法名,让restTemplateB覆盖掉了restTemplateA?文档上说@Bean这种方式默认的id是方法名,但是可以通过name或者value来改变。显然这种解释不对;我们将原来相同方法名的两个Bean放到两个不同的Config文件中,发现与改名一样,都起作用。
经过反复实验,确认是方法名的锅。在Config文件中,可以所有bean都用一个方法名,然后设置不同的name,这是符合语法规范的,但是Spring创建bean的时候同一个class文件中的同名方法只有最后一个bean可以被创建(这也是为什么拆成两个文件就正常了)。
具体为什么,翻了一通源码,感觉还是看不懂。未完待续。
测试demo的地址:https://github.com/lamyoung/demo-http