@PostConstruct用法

一、介绍:    

PostConstruct 是 Java EE(现 Jakarta EE)的注解,Spring 也支持。它用于标记一个方法,在 Bean 初始化完成后、依赖注入完成之后 立即执行。
执行时机:Bean 实例化 → 依赖注入 → @PostConstruct → Bean 准备就绪

 

二、基本用法:  

package com.csii.test.spring;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;


@Component
@Slf4j
public class TestPostConstructService {

    @PostConstruct
    public void init() {
        log.info("Bean 初始化完成,执行初始化逻辑");
        loadConfigurations();
        initializeResources();
    }

    private void loadConfigurations() {
        log.info("加载配置...");
    }

    private void initializeResources() {
        log.info("初始化资源...");
    }
}

启动项目,查看打印日志:

2026-01-20 14:43:21.266  INFO 23888 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2026-01-20 14:43:21.279  INFO 23888 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2026-01-20 14:43:21.279  INFO 23888 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.30]
2026-01-20 14:43:21.399  INFO 23888 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2026-01-20 14:43:21.399  INFO 23888 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1197 ms
2026-01-20 14:43:21.499  INFO 23888 --- [           main] c.c.t.spring.TestPostConstructService    : Bean 初始化完成,执行初始化逻辑
2026-01-20 14:43:21.499  INFO 23888 --- [           main] c.c.t.spring.TestPostConstructService    : 加载配置...
2026-01-20 14:43:21.499  INFO 23888 --- [           main] c.c.t.spring.TestPostConstructService    : 初始化资源...
2026-01-20 14:43:21.657  INFO 23888 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2026-01-20 14:43:21.896  INFO 23888 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''

 

三、常见使用场景:  

场景1:数据初始化

@Component
public class CacheManager {
    private Map<String, Object> cache;
    
    @PostConstruct
    public void initCache() {
        cache = new ConcurrentHashMap<>();
        // 从数据库加载初始数据到缓存
        loadInitialDataToCache();
        System.out.println("缓存初始化完成");
    }
}

场景2:配置验证

@Configuration
public class AppConfig {
    
    @Value("${app.max.connections}")
    private int maxConnections;
    
    @PostConstruct
    public void validateConfig() {
        if (maxConnections <= 0) {
            throw new IllegalArgumentException("最大连接数必须大于0");
        }
        System.out.println("配置验证通过");
    }
}

场景3:注册监听器或处理器:

@Component
public class EventProcessor {
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    private List<EventListener> listeners = new ArrayList<>();
    
    @PostConstruct
    public void registerListeners() {
        listeners.add(new EmailEventListener());
        listeners.add(new SmsEventListener());
        listeners.add(new LogEventListener());
        
        // 注册到事件发布器
        listeners.forEach(listener -> 
            eventPublisher.addApplicationListener(listener)
        );
    }
}

 

四、与InitializingBean接口比较

// 使用 @PostConstruct(推荐)
@Component
public class MyService1 {
    @PostConstruct
    public void init() {
        // 初始化代码
    }
}

// 使用 InitializingBean 接口
@Component
public class MyService2 implements InitializingBean {
    
    @Override
    public void afterPropertiesSet() throws Exception {
        // 初始化代码
    }
}

// 两者可以共存,执行顺序:@PostConstruct → afterPropertiesSet()

 

五、实际项目中的最佳实践  

实践1:初始化配置类

@Configuration
@PropertySource("classpath:application.properties")
public class DatabaseConfig {
    
    @Value("${spring.datasource.url}")
    private String dbUrl;
    
    @Value("${spring.datasource.username}")
    private String username;
    
    @Value("${spring.datasource.password}")
    private String password;
    
    private DataSource dataSource;
    
    @PostConstruct
    public void initDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(dbUrl);
        config.setUsername(username);
        config.setPassword(password);
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        
        this.dataSource = new HikariDataSource(config);
        System.out.println("数据源初始化完成");
    }
    
    @Bean
    public DataSource dataSource() {
        return dataSource;
    }
}

 

六、替代方案:ApplicationRunner或CommandLineRunner:

对于需要在所有Bean初始化完成后执行的启动逻辑:

@Component
@Order(1)  // 可以指定执行顺序
public class AppStartupRunner implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 在所有 Bean 初始化完成后执行
        System.out.println("应用启动完成,执行启动任务");
    }
}

// 或者使用 CommandLineRunner
@Component
public class MyCommandLineRunner implements CommandLineRunner {
    
    @Override
    public void run(String... args) throws Exception {
        // 处理命令行参数
    }
}

总结

  • @PostConstruct 在单个 Bean 初始化完成后立即执行

  • 适合执行该 Bean 自身的初始化逻辑

  • 不要在其中执行耗时操作

  • 对于需要在所有 Bean 都准备好后执行的逻辑,使用 ApplicationRunner 或 CommandLineRunner

 

--

posted on 2026-01-20 14:59  有点懒惰的大青年  阅读(0)  评论(0)    收藏  举报