SpringBoot怎么实现启动时自动执行代码

发布时间:2022-02-17 13:42:45 作者:iii
来源:亿速云 阅读:348
# SpringBoot怎么实现启动时自动执行代码

## 引言

在SpringBoot应用开发中,经常需要在项目启动时自动执行一些初始化代码,例如:
- 加载缓存数据
- 建立数据库连接池
- 初始化系统配置
- 启动定时任务
- 检查依赖服务可用性

本文将详细介绍5种实现启动自动执行代码的方式,并分析它们的适用场景和执行顺序。

## 一、@PostConstruct注解

### 基本用法
```java
import javax.annotation.PostConstruct;

@Component
public class InitService {
    
    @PostConstruct
    public void init() {
        System.out.println("使用@PostConstruct初始化");
    }
}

特点

  1. 作用于Bean的初始化方法
  2. 在依赖注入完成后执行
  3. 执行顺序早于InitializingBean
  4. 只能用于无参方法

执行时机

Bean实例化 → 依赖注入 → @PostConstruct

二、实现CommandLineRunner接口

基本实现

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {
    
    @Override
    public void run(String... args) {
        System.out.println("CommandLineRunner执行初始化");
    }
}

进阶用法(多Runner排序)

@Component
@Order(1)
public class PrimaryRunner implements CommandLineRunner {
    // 高优先级执行
}

@Component
@Order(2)
public class SecondaryRunner implements CommandLineRunner {
    // 低优先级执行
}

特点

  1. 在Spring上下文完全加载后执行
  2. 可以访问main()方法的原始参数
  3. 支持多个实现类排序执行

三、实现ApplicationRunner接口

基本实现

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationRunner implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) {
        System.out.println("ApplicationRunner执行初始化");
        System.out.println("启动参数: " + args.getOptionNames());
    }
}

与CommandLineRunner的区别

特性 ApplicationRunner CommandLineRunner
参数处理方式 结构化解析后的参数对象 原始字符串数组
参数访问 提供getOptionNames()等方法 直接访问String[] args
适用场景 需要复杂参数解析 简单参数处理

四、ApplicationListener监听事件

监听特定事件

import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class MyAppListener implements ApplicationListener<ApplicationReadyEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        System.out.println("应用已完全启动");
    }
}

常用启动事件

  1. ApplicationStartingEvent - 最早触发
  2. ApplicationEnvironmentPreparedEvent
  3. ApplicationContextInitializedEvent
  4. ApplicationPreparedEvent
  5. ApplicationStartedEvent
  6. ApplicationReadyEvent - 完全启动后触发(推荐)

执行顺序图示

启动事件序列:
Starting → EnvironmentPrepared → ContextInitialized → Prepared → Started → Ready

五、@Bean的initMethod属性

配置方式

@Configuration
public class AppConfig {
    
    @Bean(initMethod = "init")
    public DataSource dataSource() {
        return new HikariDataSource();
    }
}

public class DataSource {
    public void init() {
        System.out.println("DataSource初始化");
    }
}

特点

  1. 适用于第三方库的Bean初始化
  2. 可以与destroyMethod配合使用
  3. 执行顺序晚于@PostConstruct

六、各种方式的执行顺序对比

完整执行顺序

  1. @PostConstruct
  2. InitializingBean.afterPropertiesSet()
  3. @Bean(initMethod)
  4. ApplicationStartingEvent系列事件
  5. CommandLineRunner/ApplicationRunner
  6. ApplicationReadyEvent

验证代码示例

@Component
public class ExecutionOrderValidator {
    
    @PostConstruct
    public void postConstruct() {
        System.out.println("1. @PostConstruct");
    }

    @Bean(initMethod = "init")
    public DemoBean demoBean() {
        return new DemoBean();
    }
}

@Component
class MyRunner implements CommandLineRunner {
    @Override
    public void run(String... args) {
        System.out.println("5. CommandLineRunner");
    }
}

七、实际应用场景示例

场景1:数据库初始化

@Component
public class DatabaseInitializer implements CommandLineRunner {
    
    @Autowired
    private UserRepository userRepository;

    @Override
    public void run(String... args) {
        if(userRepository.count() == 0) {
            userRepository.save(new User("admin", "admin123"));
        }
    }
}

场景2:缓存预热

@Component
public class CacheWarmer implements ApplicationRunner {
    
    @Override
    public void run(ApplicationArguments args) {
        // 加载热点数据到Redis
        loadHotProductsToCache();
    }
}

场景3:健康检查

@Component
public class ServiceHealthChecker implements 
        ApplicationListener<ApplicationReadyEvent> {
            
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        checkDatabaseConnection();
        checkThirdPartyServices();
    }
}

八、注意事项

  1. 避免阻塞:启动代码不应长时间阻塞,否则影响应用启动
  2. 异常处理:初始化失败应明确抛出异常,避免静默失败
  3. 执行时间:复杂初始化考虑异步执行
  4. 环境判断:根据不同Profile执行不同逻辑
    
    @Profile("prod")
    @Component
    public class ProdInitializer {
       // 生产环境特有初始化
    }
    

结论

SpringBoot提供了灵活的启动初始化方案,根据需求可以选择: - 简单初始化:@PostConstruct - 带参数初始化:CommandLineRunner/ApplicationRunner - 精确事件控制:ApplicationListener - 第三方库集成:@Bean(initMethod)

建议根据具体场景选择最合适的方式,并注意各方式的执行顺序和特性差异。

最佳实践:将关键初始化代码放在ApplicationReadyEvent监听器中,确保所有Bean都可用后再执行初始化操作。 “`

推荐阅读:
  1. 怎么让docker中的mysql启动时自动执行sql语句
  2. Springboot如何实现自动装配

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

springboot

上一篇:C#折线图控件怎么使用

下一篇:JavaScript的库urlcat有什么作用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》