You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot中@Autowired注入TokenService为空,带@Qualifier时失效求解决方案

问题原因分析

这是典型的循环依赖+Bean初始化顺序冲突导致的注入失败:

  1. TokenServiceImpl的构造函数依赖名为rstProxy的RestTemplate Bean;
  2. 而rstProxy这个RestTemplate的创建方法restTemplateWithProxy()中,又需要注入TokenService来初始化AuthorizationInterceptor;
  3. Spring初始化Bean时,会先尝试创建TokenServiceImpl,发现需要rstProxy,于是转而去创建rstProxy的RestTemplate;但创建RestTemplate时,TokenService还未完成初始化,此时Application类中@Autowired的tokenService还未被赋值,因此是null;最终整个循环依赖导致TokenServiceImpl无法正常初始化,Application里的tokenService自然也是null。

当你移除@Qualifier("rstProxy")后,TokenServiceImpl会使用其他可用的RestTemplate(比如默认的无代理实例),不会触发这个循环依赖链,因此注入正常。

解决方案(保留@Qualifier的前提下)

方案1:使用ObjectProvider延迟获取TokenService

ObjectProvider是Spring提供的用于延迟获取Bean的工具,能避免在Bean初始化阶段直接触发循环依赖:

修改Application类中的restTemplateWithProxy方法:

@Bean("rstProxy")
public RestTemplate restTemplateWithProxy(ObjectProvider<TokenService> tokenServiceProvider) {
    final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(new StringHttpMessageConverter());
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    messageConverters.add(new MappingJackson2HttpMessageConverter());

    final RestTemplate restTemplate = new RestTemplate();

    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    // 延迟获取TokenService,直到真正需要时才初始化
    interceptors.add(new AuthorizationInterceptor(tokenServiceProvider.getObject()));
    restTemplate.setInterceptors(interceptors);
    restTemplate.getMessageConverters().addAll(messageConverters);

    restTemplate.setRequestFactory(factory);
    return restTemplate;
}

方案2:将AuthorizationInterceptor注册为Spring Bean

把AuthorizationInterceptor交给Spring容器管理,利用Spring的三级缓存机制自动处理循环依赖:

  1. 给AuthorizationInterceptor添加@Component注解,让Spring扫描并管理它:
@Component
public class AuthorizationInterceptor implements ClientHttpRequestInterceptor {
    private final TokenService tokenService;

    // 构造器注入TokenService
    public AuthorizationInterceptor(TokenService tokenService) {
        this.tokenService = tokenService;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // 你的拦截逻辑
        return execution.execute(request, body);
    }
}
  1. 修改Application类的restTemplateWithProxy方法,直接注入AuthorizationInterceptor:
@Bean("rstProxy")
public RestTemplate restTemplateWithProxy(AuthorizationInterceptor authorizationInterceptor) {
    final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(new StringHttpMessageConverter());
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
    messageConverters.add(new MappingJackson2HttpMessageConverter());

    final RestTemplate restTemplate = new RestTemplate();

    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(authorizationInterceptor);
    restTemplate.setInterceptors(interceptors);
    restTemplate.getMessageConverters().addAll(messageConverters);

    restTemplate.setRequestFactory(factory);
    return restTemplate;
}

方案3:使用@Lazy延迟初始化Bean

通过@Lazy注解打破循环依赖的初始化链,让Spring先完成其中一个Bean的初始化:

方式A:在TokenServiceImpl的RestTemplate参数上添加@Lazy

@Service
public class TokenServiceImpl implements TokenService{

    private final Settings settings;
    private final RestTemplate restTemplate;

    @Autowired
    public TokenServiceImpl(Settings settings, @Qualifier("rstProxy") @Lazy RestTemplate restTemplate) {
        this.settings= settings;
        this.restTemplate = restTemplate;
    }
    //...
}

方式B:在Application类的TokenService注入上添加@Lazy

@SpringBootApplication
@EnableAsync
@EnableScheduling
public class Application extends SpringBootServletInitializer {

    @Autowired
    @Lazy
    private TokenService tokenService;

    //... restTemplateWithProxy方法不变
}

@Lazy会让Spring生成一个代理对象,直到第一次真正使用时才初始化目标Bean,从而绕过初始化阶段的循环依赖。

内容的提问来源于stack exchange,提问作者user1814879

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 15:58:19