Spring Boot Configuration类中@Bean注解与实例变量流转相关疑问
示例代码
@Configuration public class UserConfiguration{ RestTemplate restTemplate; @Bean @Named("userRestTemplate") public RestTemplate userRestTemplate(RestTemplateBuilder restTemplateBuilder) { RestTemplate restTemplate = restTemplateBuilder.build(); //restTemplate.getMessageConverters().add(0, createMappingJacksonHttpMessageConverter()); this.restTemplate = restTemplate; return restTemplate; } @Bean public UserDetail userDetail() { UserDetail user = new UserDetail(); user.setTemplate(restTemplate); return user; } }
问题解答
1. userRestTemplate是否可以修改配置类的实例变量restTemplate?
可以。被@Configuration标注的类本身会被Spring作为单例Bean托管,你在userRestTemplate()方法中执行this.restTemplate = restTemplate时,就是直接给当前配置类实例的成员变量赋值,该修改完全生效。
2. userDetail Bean是否能获取到userRestTemplate更新后的restTemplate值?
默认场景下完全可以。Spring实例化@Bean对象时会自动解析依赖顺序:userDetail的初始化依赖了成员变量restTemplate,而这个变量只有在userRestTemplate方法执行完成后才会被赋值,因此Spring会优先实例化userRestTemplate,再实例化userDetail,此时setTemplate传入的就是userRestTemplate创建的RestTemplate实例。
3. 如果拿不到更新后的值,此时setTemplate的入参是什么?
只有当你手动调整了Bean的加载顺序,导致userDetail比userRestTemplate更早实例化时才会出现该情况,常见触发场景包括给userDetail加了反向的@DependsOn注解、userRestTemplate和userDetail出现循环依赖、给userRestTemplate加了@Lazy懒加载注解等。此时成员变量restTemplate还没有被赋值,setTemplate的入参就是null。
最佳实践建议
你当前这种通过配置类成员变量传递Bean的写法不推荐,很容易因为加载顺序异常出现空指针问题,更稳妥的写法有两种:
- 方法1:在
userDetail的Bean方法入参中直接声明依赖
@Bean public UserDetail userDetail(@Named("userRestTemplate") RestTemplate restTemplate) { UserDetail user = new UserDetail(); user.setTemplate(restTemplate); return user; }
- 方法2:直接调用内部的
userRestTemplate()方法@Configuration类会被CGLIB动态代理,多次调用内部的@Bean方法只会返回Spring管理的单例实例,不会重复创建新对象:
@Bean public UserDetail userDetail() { UserDetail user = new UserDetail(); user.setTemplate(userRestTemplate()); return user; }
内容的提问来源于stack exchange,提问作者Surbhi Grover
相关产品推荐
相关产品推荐

