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

Spring中@PostConstruct执行两次的原因及修复方案问询

Spring中@PostConstruct方法执行两次的问题修复

问题背景

在Spring Web应用中,通过@PostConstruct与@Bean实现启动初始化,但发现MyCache类的init()方法被执行了两次。

代码示例

public class MyCache<T> {
    @PostConstruct
    public void init() {
        System.out.println("inittttttttttt");
        // 初始化逻辑
    }
}

@Configuration
@EnableScheduling
public class AppConfig {
    @Bean
    public MyCache<MyData> myCache() {
        return new MyCache<MyData>();
    }
}

public class TextFilter {
    private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
    private MyCache<MyData> cache;

    public TextFilter() {
        this.context.scan("com.sensitive_words.utils");
        this.context.refresh();
        this.cache = this.context.getBean(MyCache.class);
    }

    public String filter(String originalText) {
        return this.cache.get().filter(originalText);
    }
}

日志输出

2022-10-30 13:53:38.837  INFO 106994 --- [           main] y.c.s.SensitiveWordsApplication          : Starting SensitiveWordsApplication using Java 11.0.16 on yves-Inspiron-5488 with PID 106994 (/home/yves/java_ws/sensitive_words/target/classes started by yves in /home/yves/java_ws/sensitive_words)
2022-10-30 13:53:38.839  INFO 106994 --- [           main] y.c.s.SensitiveWordsApplication          : No active profile set, falling back to 1 default profile: "default"
2022-10-30 13:53:39.545  INFO 106994 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8090 (http)
2022-10-30 13:53:39.559  INFO 106994 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-10-30 13:53:39.560  INFO 106994 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]
2022-10-30 13:53:39.654  INFO 106994 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-10-30 13:53:39.654  INFO 106994 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 763 ms
inittttttttttt
2022-10-30 13:53:39.769  INFO 106994 --- [           main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
inittttttttttt
2022-10-30 13:53:40.080  INFO 106994 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8090 (http) with context path ''
2022-10-30 13:53:40.096  INFO 106994 --- [           main] y.c.s.SensitiveWordsApplication          : Started SensitiveWordsApplication in 1.64 seconds (JVM running for 2.341)

原因分析

核心问题是存在两个独立的Spring容器:

  1. Spring Web应用启动时会自动创建根容器(ServletWebServerApplicationContext),扫描配置类并初始化MyCache Bean,触发第一次init()执行。
  2. TextFilter构造函数中手动创建了AnnotationConfigApplicationContext,并扫描同一个包路径,导致第二次初始化MyCache实例,触发第二次init()执行。

修复方案

步骤1:重构TextFilter,使用Spring依赖注入

移除手动创建的容器实例,通过Spring的依赖注入获取MyCache,同时将TextFilter声明为Spring管理的Bean:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class TextFilter {
    private final MyCache<MyData> cache;

    @Autowired
    public TextFilter(MyCache<MyData> cache) {
        this.cache = cache;
    }

    public String filter(String originalText) {
        return this.cache.get().filter(originalText);
    }
}

步骤2:确保TextFilter被Spring扫描到

保证TextFilter所在的包在Spring根容器的扫描范围内(比如与AppConfig同包,或通过@ComponentScan注解明确指定扫描路径)。

步骤3:通过Spring容器获取TextFilter实例

禁止手动new TextFilter(),需从Spring容器中获取实例:

// 在Spring管理的类中直接注入
@Autowired
private TextFilter textFilter;

// 或通过ApplicationContext获取
TextFilter textFilter = applicationContext.getBean(TextFilter.class);

通过以上操作,整个应用只会维护一个Spring容器,MyCache仅会被初始化一次,init()方法也只会执行一次。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:40:38