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

Spring Boot应用出现Bean循环引用错误的原因及修复方法

循环依赖产生原因
  • @Configuration标注的类本身也是Spring托管的Bean,其完整初始化流程为:实例化 -> 依赖注入 -> 执行@PostConstruct生命周期回调 -> 完成初始化
  • 你的代码中@PostConstruct标注的startMonitoring方法会调用fetchWeatherData,而fetchWeatherData直接调用了同类下的@Bean方法restTemplate()
  • Spring对@Configuration类会做CGLIB代理,调用类内部的@Bean方法默认会尝试从Spring容器中获取对应Bean实例。此时要创建RestTemplate,需要先保证其定义所在的配置类AppConfig已经完成全量初始化,但AppConfig还卡在@PostConstruct的执行流程中,二者形成依赖循环。
修复方案

方案1:注入RestTemplate实例而非直接调用@Bean方法

将RestTemplate作为AppConfig的依赖注入,避免在初始化阶段触发RestTemplate的创建逻辑:

@Configuration
public class AppConfig {

    @Autowired
    private Environment env;
    // 提前注入RestTemplate实例
    @Autowired
    private RestTemplate restTemplate;
    private List<Weather> weathers = new ArrayList<>();

    @Bean
    public RestTemplate restTemplate() {
        var factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(3000);
        factory.setReadTimeout(3000);
        return new RestTemplate(factory);
    }

    @PostConstruct
    public void startMonitoring() {
        // 原有逻辑不变
        String url = env.getProperty("openWeatherUrl");
        String apiKey = env.getProperty("openWeatherApiKey");

        try (InputStream resource = app.class.getResourceAsStream("/config.csv")) {
            CSVReader reader = new CSVReader(new InputStreamReader(resource));
            String[] lineInArray;
            while ((lineInArray = reader.readNext()) != null) {
                Weather weather = new Weather();
                if (!lineInArray[0].contains("city")) {
                    weather.setCity(lineInArray[0]);
                } else {
                    continue;
                }

                if (!lineInArray[1].contains("temperaturesLimit")) {
                    weather.setTemperaturesLimit(Float.parseFloat(lineInArray[2]));
                }
                if (!lineInArray[2].contains("temperaturesLimit")) {
                    weather.setFrequency(Integer.parseInt(lineInArray[2]));
                }

                URI uri = new URI(url + "?q=" + weather.getCity() + "&units=metric&APPID=" + apiKey);
                weather.setUri(uri);
                weathers.add(weather);
            }
        } catch (IOException | CsvValidationException | URISyntaxException e) {
            System.out.println(e.getMessage());
        }
        fetchWeatherData();
    }

    void fetchWeatherData(){
        // 直接使用注入的restTemplate实例,不调用@Bean方法
        weathers.forEach(weather -> {
            var res = restTemplate.getForEntity(weather.getUri(), Weather.class);
        });
    }
}

方案2:延迟执行初始化逻辑到容器完全启动后

将startMonitoring方法的触发时机改为容器全量初始化完成后,避免在Bean初始化阶段调用@Bean方法:

// 移除@PostConstruct注解,改用@EventListener监听容器刷新完成事件
@EventListener(ContextRefreshedEvent.class)
public void startMonitoring() {
    // 原有逻辑保持不变
}

方案3:拆分配置类

将RestTemplate的Bean定义移动到独立的配置类中,避免RestTemplate的创建依赖当前AppConfig的初始化状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 08:54:04