当前位置: 代码网 > it编程>编程语言>Java > SpringBoot启动时执行特定代码的10种方式

SpringBoot启动时执行特定代码的10种方式

2025年10月17日 Java 我要评论
1. 引言在实际的 spring boot 项目开发中,我们经常需要在应用启动时执行一些特定的初始化代码,比如缓存预热、数据初始化、配置加载、服务注册等。spring boot 提供了多种灵活的方式来

1. 引言

在实际的 spring boot 项目开发中,我们经常需要在应用启动时执行一些特定的初始化代码,比如缓存预热、数据初始化、配置加载、服务注册等。spring boot 提供了多种灵活的方式来实现启动时执行代码的需求。

本文将全面深入地介绍 spring boot 中启动时执行特定代码的 10 种方式,涵盖从简单到复杂的各种场景,并通过详细的代码示例、执行顺序分析和流程图帮助读者彻底掌握这一重要技术。

2. 启动时执行代码的应用场景

2.1 常见应用场景

  1. 数据初始化:数据库表结构初始化、基础数据导入
  2. 缓存预热:加载热点数据到缓存中
  3. 配置验证:检查外部配置的正确性 
  4. 服务注册:向注册中心注册服务实例
  5. 连接建立:建立数据库连接池、redis 连接等
  6. 文件检查:检查必要的配置文件或资源文件
  7. 定时任务启动:初始化并启动定时任务
  8. 全局变量初始化:初始化应用级别的全局变量

2.2 需求分类

需求类型执行时机典型实现方式
bean初始化后bean创建完成后@postconstruct
应用启动后应用完全启动后applicationrunner
特定条件初始化满足条件时执行@conditional + @bean
顺序执行多个任务按顺序执行@order注解

3. 方法一:@postconstruct 注解

3.1 基本使用

@postconstruct 是 jsr-250 规范中的注解,用于标记在 bean 初始化完成后执行的方法。

@component
public class postconstructexample {
    
    private static final logger logger = loggerfactory.getlogger(postconstructexample.class);
    
    @postconstruct
    public void init() {
        logger.info("@postconstruct方法执行 - 开始初始化工作");
        
        // 执行初始化逻辑
        initializecache();
        loadconfiguration();
        validateenvironment();
        
        logger.info("@postconstruct方法执行 - 初始化完成");
    }
    
    private void initializecache() {
        logger.info("初始化缓存数据...");
        // 模拟缓存预热
        try {
            thread.sleep(1000);
        } catch (interruptedexception e) {
            thread.currentthread().interrupt();
        }
    }
    
    private void loadconfiguration() {
        logger.info("加载配置文件...");
        // 模拟配置加载
    }
    
    private void validateenvironment() {
        logger.info("验证环境配置...");
        // 模拟环境验证
    }
}

3.2 执行时机和特点

执行时机

  • 在依赖注入完成之后
  • 在 @bean 的 initmethod 之前
  • 在 bean 的生命周期早期

特点

  • 执行在 bean 的初始化阶段
  • 只执行一次
  • 不能有参数
  • 不能有返回值
  • 可以抛出异常(会阻止 bean 的创建)

4. 方法二:initializingbean 接口

4.1 基本使用

initializingbean 接口提供了一个 afterpropertiesset() 方法,在 bean 的属性设置完成后执行。

@component
public class initializingbeanexample implements initializingbean {
    
    private static final logger logger = loggerfactory.getlogger(initializingbeanexample.class);
    
    private final environment environment;
    private string appname;
    private string appversion;
    
    public initializingbeanexample(environment environment) {
        this.environment = environment;
    }
    
    @override
    public void afterpropertiesset() throws exception {
        logger.info("initializingbean.afterpropertiesset()方法执行");
        
        // 获取配置信息
        this.appname = environment.getproperty("spring.application.name", "unknown");
        this.appversion = environment.getproperty("app.version", "1.0.0");
        
        // 执行初始化逻辑
        initializeapplication();
        setupglobalvariables();
        
        logger.info("应用初始化完成: {} v{}", appname, appversion);
    }
    
    private void initializeapplication() {
        logger.info("初始化应用核心组件...");
        // 模拟核心组件初始化
    }
    
    private void setupglobalvariables() {
        logger.info("设置全局变量...");
        // 模拟全局变量设置
    }
    
    public string getappinfo() {
        return string.format("%s v%s", appname, appversion);
    }
}

4.2 执行顺序

@component
public class executionorderexample implements initializingbean {
    
    @postconstruct
    public void postconstruct() {
        system.out.println("1. @postconstruct 执行");
    }
    
    @override
    public void afterpropertiesset() throws exception {
        system.out.println("2. initializingbean.afterpropertiesset() 执行");
    }
    
    @bean(initmethod = "initmethod")
    public demobean demobean() {
        return new demobean();
    }
    
    public static class demobean {
        public void initmethod() {
            system.out.println("3. @bean initmethod 执行");
        }
    }
}

5. 方法三:@bean 的 initmethod 属性

5.1 基本使用

在 @bean 注解中指定 initmethod 属性,可以在 bean 初始化完成后执行指定的方法。

@configuration
public class initmethodconfig {
    
    private static final logger logger = loggerfactory.getlogger(initmethodconfig.class);
    
    @bean(initmethod = "initialize", destroymethod = "cleanup")
    public databaseconnection databaseconnection() {
        logger.info("创建databaseconnection bean实例");
        return new databaseconnection();
    }
    
    public static class databaseconnection {
        
        public void initialize() {
            logger.info("databaseconnection initmethod执行 - 建立数据库连接");
            // 模拟数据库连接建立
            try {
                thread.sleep(2000);
                logger.info("数据库连接建立成功");
            } catch (interruptedexception e) {
                thread.currentthread().interrupt();
                logger.error("数据库连接建立失败", e);
            }
        }
        
        public void cleanup() {
            logger.info("databaseconnection destroymethod执行 - 关闭数据库连接");
            // 模拟资源清理
        }
        
        public void query(string sql) {
            logger.info("执行查询: {}", sql);
        }
    }
}

5.2 复杂示例

@configuration
public class complexinitmethodexample {
    
    @bean(initmethod = "start", destroymethod = "stop")
    public messagequeueconsumer messagequeueconsumer() {
        return new messagequeueconsumer();
    }
    
    @bean(initmethod = "initializeconnectionpool")
    public connectionpool connectionpool() {
        return new connectionpool();
    }
    
    public static class messagequeueconsumer {
        public void start() {
            system.out.println("消息队列消费者启动...");
            // 模拟启动逻辑
        }
        
        public void stop() {
            system.out.println("消息队列消费者停止...");
            // 模拟停止逻辑
        }
    }
    
    public static class connectionpool {
        public void initializeconnectionpool() {
            system.out.println("初始化数据库连接池...");
            // 模拟连接池初始化
        }
    }
}

6. 方法四:applicationrunner 接口

6.1 基本使用

applicationrunner 接口在 spring boot 应用完全启动后执行,可以访问 applicationarguments

@component
@order(1)
public class primaryapplicationrunner implements applicationrunner {
    
    private static final logger logger = loggerfactory.getlogger(primaryapplicationrunner.class);
    
    private final environment environment;
    private final userrepository userrepository;
    
    public primaryapplicationrunner(environment environment, userrepository userrepository) {
        this.environment = environment;
        this.userrepository = userrepository;
    }
    
    @override
    public void run(applicationarguments args) throws exception {
        logger.info("primaryapplicationrunner开始执行 - 应用启动完成");
        
        // 获取启动参数
        logger.info("启动参数: {}", arrays.tostring(args.getsourceargs()));
        logger.info("非选项参数: {}", args.getnonoptionargs());
        logger.info("选项参数名称: {}", args.getoptionnames());
        
        // 执行核心初始化逻辑
        initializesystem();
        preloaddata();
        startbackgroundservices();
        
        logger.info("primaryapplicationrunner执行完成");
    }
    
    private void initializesystem() {
        logger.info("初始化系统核心组件...");
        
        // 检查数据库连接
        checkdatabaseconnection();
        
        // 验证必要的配置
        validaterequiredconfigurations();
        
        // 初始化系统缓存
        initializesystemcache();
    }
    
    private void checkdatabaseconnection() {
        try {
            long usercount = userrepository.count();
            logger.info("数据库连接正常,用户数量: {}", usercount);
        } catch (exception e) {
            logger.error("数据库连接检查失败", e);
            throw new runtimeexception("数据库连接失败", e);
        }
    }
    
    private void validaterequiredconfigurations() {
        string[] requiredprops = {
            "spring.datasource.url",
            "spring.redis.host",
            "app.security.secret-key"
        };
        
        for (string prop : requiredprops) {
            if (!environment.containsproperty(prop)) {
                throw new illegalstateexception("必要的配置项缺失: " + prop);
            }
        }
        logger.info("所有必要配置项验证通过");
    }
    
    private void initializesystemcache() {
        logger.info("初始化系统缓存...");
        // 模拟缓存初始化
    }
    
    private void preloaddata() {
        logger.info("预加载热点数据...");
        // 模拟数据预加载
    }
    
    private void startbackgroundservices() {
        logger.info("启动后台服务...");
        // 模拟后台服务启动
    }
}

6.2 多个 applicationrunner 的执行顺序

@component
@order(1)
public class firstapplicationrunner implements applicationrunner {
    
    @override
    public void run(applicationarguments args) throws exception {
        system.out.println("第一个applicationrunner执行 - order(1)");
        // 执行最高优先级的初始化任务
    }
}

@component  
@order(2)
public class secondapplicationrunner implements applicationrunner {
    
    @override
    public void run(applicationarguments args) throws exception {
        system.out.println("第二个applicationrunner执行 - order(2)");
        // 执行次优先级的初始化任务
    }
}

@component
@order(3)
public class thirdapplicationrunner implements applicationrunner {
    
    @override
    public void run(applicationarguments args) throws exception {
        system.out.println("第三个applicationrunner执行 - order(3)");
        // 执行最低优先级的初始化任务
    }
}

7. 方法五:commandlinerunner 接口

7.1 基本使用

commandlinerunner 接口与 applicationrunner 类似,但接收的是原始的字符串数组参数。

@component
@order(2)
public class commandlinerunnerexample implements commandlinerunner {
    
    private static final logger logger = loggerfactory.getlogger(commandlinerunnerexample.class);
    
    private final datasource datasource;
    private final redistemplate<string, object> redistemplate;
    
    public commandlinerunnerexample(datasource datasource, redistemplate<string, object> redistemplate) {
        this.datasource = datasource;
        this.redistemplate = redistemplate;
    }
    
    @override
    public void run(string... args) throws exception {
        logger.info("commandlinerunner开始执行 - 参数数量: {}", args.length);
        
        // 输出所有命令行参数
        for (int i = 0; i < args.length; i++) {
            logger.info("参数 {}: {}", i, args[i]);
        }
        
        // 执行数据源相关的初始化
        initializedatasource();
        
        // 执行缓存相关的初始化
        initializecache();
        
        // 执行其他初始化任务
        performsanitychecks();
        
        logger.info("commandlinerunner执行完成");
    }
    
    private void initializedatasource() {
        logger.info("初始化数据源...");
        try {
            // 测试数据库连接
            try (connection connection = datasource.getconnection()) {
                databasemetadata metadata = connection.getmetadata();
                logger.info("数据库连接成功: {} {}", 
                    metadata.getdatabaseproductname(), 
                    metadata.getdatabaseproductversion());
            }
        } catch (sqlexception e) {
            logger.error("数据源初始化失败", e);
            throw new runtimeexception("数据源初始化失败", e);
        }
    }
    
    private void initializecache() {
        logger.info("初始化缓存...");
        try {
            // 测试redis连接
            redistemplate.opsforvalue().set("startup-test", "success", duration.ofseconds(30));
            string result = (string) redistemplate.opsforvalue().get("startup-test");
            logger.info("redis连接测试: {}", "success".equals(result) ? "成功" : "失败");
        } catch (exception e) {
            logger.error("缓存初始化失败", e);
            throw new runtimeexception("缓存初始化失败", e);
        }
    }
    
    private void performsanitychecks() {
        logger.info("执行系统健康检查...");
        // 模拟系统检查
        checkdiskspace();
        checkmemoryusage();
    }
    
    private void checkdiskspace() {
        logger.info("检查磁盘空间...");
        // 模拟磁盘空间检查
    }
    
    private void checkmemoryusage() {
        logger.info("检查内存使用情况...");
        // 模拟内存检查
    }
}

8. 方法六:@eventlistener 监听 contextrefreshedevent

8.1 基本使用

通过监听 spring 上下文刷新完成事件来执行初始化代码。

@component
public class contextrefreshedeventlistener {
    
    private static final logger logger = loggerfactory.getlogger(contextrefreshedeventlistener.class);
    
    private final applicationcontext applicationcontext;
    private final systemconfigservice systemconfigservice;
    
    public contextrefreshedeventlistener(applicationcontext applicationcontext, 
                                       systemconfigservice systemconfigservice) {
        this.applicationcontext = applicationcontext;
        this.systemconfigservice = systemconfigservice;
    }
    
    @eventlistener(contextrefreshedevent.class)
    public void oncontextrefreshed(contextrefreshedevent event) {
        // 避免在子容器中重复执行
        if (event.getapplicationcontext().getparent() != null) {
            return;
        }
        
        logger.info("contextrefreshedevent事件触发 - spring容器刷新完成");
        
        // 执行初始化逻辑
        loadsystemconfigurations();
        initializethirdpartyservices();
        registersystembeans();
        
        logger.info("contextrefreshedevent事件处理完成");
    }
    
    private void loadsystemconfigurations() {
        logger.info("加载系统配置...");
        
        try {
            // 从数据库加载系统配置
            map<string, string> configs = systemconfigservice.loadallconfigs();
            logger.info("加载了 {} 条系统配置", configs.size());
            
            // 将配置设置到应用上下文中
            configs.foreach((key, value) -> {
                logger.debug("系统配置: {} = {}", key, value);
            });
            
        } catch (exception e) {
            logger.error("系统配置加载失败", e);
            throw new runtimeexception("系统配置加载失败", e);
        }
    }
    
    private void initializethirdpartyservices() {
        logger.info("初始化第三方服务...");
        
        // 检查所有需要的bean是否已正确初始化
        string[] requiredbeans = {
            "datasource",
            "redistemplate",
            "resttemplate"
        };
        
        for (string beanname : requiredbeans) {
            if (applicationcontext.containsbean(beanname)) {
                object bean = applicationcontext.getbean(beanname);
                logger.info("bean {} 初始化成功: {}", beanname, bean.getclass().getsimplename());
            } else {
                logger.warn("bean {} 未找到", beanname);
            }
        }
    }
    
    private void registersystembeans() {
        logger.info("注册系统bean...");
        // 模拟系统bean注册
    }
}

8.2 其他相关事件

@component
public class multipleeventlisteners {
    
    private static final logger logger = loggerfactory.getlogger(multipleeventlisteners.class);
    
    /**
     * 应用启动事件
     */
    @eventlistener(applicationstartedevent.class)
    public void onapplicationstarted(applicationstartedevent event) {
        logger.info("应用程序启动完成 - applicationstartedevent");
    }
    
    /**
     * 应用准备就绪事件
     */
    @eventlistener(applicationreadyevent.class)
    public void onapplicationready(applicationreadyevent event) {
        logger.info("应用程序准备就绪 - applicationreadyevent");
        // 可以在这里执行一些需要在应用完全就绪后执行的任务
    }
    
    /**
     * 应用启动失败事件
     */
    @eventlistener(applicationfailedevent.class)
    public void onapplicationfailed(applicationfailedevent event) {
        logger.error("应用程序启动失败 - applicationfailedevent", event.getexception());
        // 可以在这里执行清理操作或发送告警
    }
}

9. 方法七:spring boot 的 applicationlistener

9.1 基本使用

实现 applicationlistener 接口来监听特定的事件。

@component
public class customapplicationlistener implements applicationlistener<applicationreadyevent> {
    
    private static final logger logger = loggerfactory.getlogger(customapplicationlistener.class);
    
    private final metricservice metricservice;
    private final healthcheckservice healthcheckservice;
    
    public customapplicationlistener(metricservice metricservice, 
                                   healthcheckservice healthcheckservice) {
        this.metricservice = metricservice;
        this.healthcheckservice = healthcheckservice;
    }
    
    @override
    public void onapplicationevent(applicationreadyevent event) {
        logger.info("applicationlistener收到applicationreadyevent - 开始执行启动任务");
        
        // 执行系统健康检查
        performhealthchecks();
        
        // 初始化监控指标
        initializemetrics();
        
        // 启动后台监控任务
        startmonitoringtasks();
        
        logger.info("applicationlistener启动任务执行完成");
    }
    
    private void performhealthchecks() {
        logger.info("执行系统健康检查...");
        
        try {
            healthcheckresult result = healthcheckservice.performcomprehensivecheck();
            
            if (result.ishealthy()) {
                logger.info("系统健康检查通过: {}", result.getmessage());
            } else {
                logger.error("系统健康检查失败: {}", result.getmessage());
                // 可以根据严重程度决定是否终止启动
                if (result.iscritical()) {
                    throw new runtimeexception("关键健康检查失败: " + result.getmessage());
                }
            }
        } catch (exception e) {
            logger.error("健康检查执行异常", e);
            throw new runtimeexception("健康检查失败", e);
        }
    }
    
    private void initializemetrics() {
        logger.info("初始化系统监控指标...");
        
        // 注册自定义指标
        metricservice.registercustommetrics();
        
        // 初始化性能基准
        metricservice.initializeperformancebaselines();
        
        logger.info("监控指标初始化完成");
    }
    
    private void startmonitoringtasks() {
        logger.info("启动后台监控任务...");
        
        // 启动性能监控
        metricservice.startperformancemonitoring();
        
        // 启动资源使用监控
        metricservice.startresourcemonitoring();
        
        logger.info("后台监控任务启动完成");
    }
}

10. 方法八:@configuration 类的静态代码块

10.1 基本使用

在配置类中使用静态代码块在类加载时执行代码。

@configuration
public class staticblockconfiguration {
    
    private static final logger logger = loggerfactory.getlogger(staticblockconfiguration.class);
    
    // 静态代码块 - 在类加载时执行
    static {
        logger.info("staticblockconfiguration类加载 - 静态代码块执行");
        
        // 执行一些类级别的初始化
        initializenativelibraries();
        setupsecurityproviders();
        configurelogging();
    }
    
    private static void initializenativelibraries() {
        logger.info("初始化本地库...");
        // 模拟本地库初始化
        try {
            // 加载本地库
            // system.loadlibrary("native-lib");
            logger.info("本地库初始化完成");
        } catch (exception e) {
            logger.error("本地库初始化失败", e);
        }
    }
    
    private static void setupsecurityproviders() {
        logger.info("设置安全提供者...");
        // 模拟安全设置
    }
    
    private static void configurelogging() {
        logger.info("配置日志系统...");
        // 模拟日志配置
    }
    
    @bean
    public systeminitializer systeminitializer() {
        logger.info("创建systeminitializer bean");
        return new systeminitializer();
    }
    
    public static class systeminitializer {
        public systeminitializer() {
            logger.info("systeminitializer构造函数执行");
        }
    }
}

11. 方法九:smartlifecycle 接口

11.1 基本使用

smartlifecycle 接口提供了更精细的生命周期控制。

@component
public class customsmartlifecycle implements smartlifecycle {
    
    private static final logger logger = loggerfactory.getlogger(customsmartlifecycle.class);
    
    private volatile boolean running = false;
    private final taskscheduler taskscheduler;
    private scheduledfuture<?> scheduledtask;
    
    public customsmartlifecycle(taskscheduler taskscheduler) {
        this.taskscheduler = taskscheduler;
    }
    
    @override
    public void start() {
        logger.info("customsmartlifecycle开始启动");
        
        if (!running) {
            // 执行启动逻辑
            initializeservices();
            startbackgroundtasks();
            running = true;
            
            logger.info("customsmartlifecycle启动完成");
        }
    }
    
    @override
    public void stop() {
        logger.info("customsmartlifecycle开始停止");
        
        if (running) {
            // 执行停止逻辑
            stopbackgroundtasks();
            cleanupresources();
            running = false;
            
            logger.info("customsmartlifecycle停止完成");
        }
    }
    
    @override
    public boolean isrunning() {
        return running;
    }
    
    @override
    public int getphase() {
        // 返回一个相位值,控制启动和停止的顺序
        return 0;
    }
    
    @override
    public boolean isautostartup() {
        return true;
    }
    
    private void initializeservices() {
        logger.info("初始化后台服务...");
        // 模拟服务初始化
    }
    
    private void startbackgroundtasks() {
        logger.info("启动后台任务...");
        
        // 启动定时任务
        scheduledtask = taskscheduler.scheduleatfixedrate(() -> {
            logger.debug("执行后台任务...");
            // 模拟后台任务执行
        }, duration.ofseconds(30));
    }
    
    private void stopbackgroundtasks() {
        logger.info("停止后台任务...");
        
        if (scheduledtask != null && !scheduledtask.iscancelled()) {
            scheduledtask.cancel(true);
            logger.info("后台任务已停止");
        }
    }
    
    private void cleanupresources() {
        logger.info("清理资源...");
        // 模拟资源清理
    }
}

12. 方法十:@conditional 条件化初始化

12.1 基本使用

根据条件决定是否执行初始化逻辑。

@configuration
public class conditionalinitializationconfig {
    
    private static final logger logger = loggerfactory.getlogger(conditionalinitializationconfig.class);
    
    @bean
    @conditionalonproperty(name = "app.feature.cache.enabled", havingvalue = "true")
    public cacheinitializer cacheinitializer() {
        logger.info("创建cacheinitializer - 缓存功能已启用");
        return new cacheinitializer();
    }
    
    @bean
    @conditionalonclass(name = "com.example.externalservice")
    public externalserviceinitializer externalserviceinitializer() {
        logger.info("创建externalserviceinitializer - 检测到externalservice类");
        return new externalserviceinitializer();
    }
    
    @bean
    @conditionalonexpression("${app.mode:dev} == 'prod'")
    public productioninitializer productioninitializer() {
        logger.info("创建productioninitializer - 生产环境模式");
        return new productioninitializer();
    }
    
    @bean
    @conditionalonwebapplication
    public webapplicationinitializer webapplicationinitializer() {
        logger.info("创建webapplicationinitializer - web应用环境");
        return new webapplicationinitializer();
    }
    
    public static class cacheinitializer {
        @postconstruct
        public void init() {
            logger.info("初始化缓存系统...");
            // 模拟缓存初始化
        }
    }
    
    public static class externalserviceinitializer {
        @postconstruct
        public void init() {
            logger.info("初始化外部服务...");
            // 模拟外部服务初始化
        }
    }
    
    public static class productioninitializer {
        @postconstruct
        public void init() {
            logger.info("执行生产环境特定初始化...");
            // 生产环境特定的初始化逻辑
        }
    }
    
    public static class webapplicationinitializer {
        @postconstruct
        public void init() {
            logger.info("执行web应用特定初始化...");
            // web应用特定的初始化逻辑
        }
    }
}

13. 执行顺序和优先级

13.1 完整的执行顺序流程图

graph td
    a[spring boot应用启动] --> b[加载配置类静态代码块]
    b --> c[创建bean实例]
    c --> d[依赖注入]
    d --> e[@postconstruct方法]
    e --> f[initializingbean.afterpropertiesset]
    f --> g[@bean initmethod]
    g --> h[contextrefreshedevent事件]
    h --> i[applicationrunner.run]
    i --> j[commandlinerunner.run]
    j --> k[applicationreadyevent事件]
    k --> l[应用完全就绪]
    
    style b fill:#e1f5fe
    style e fill:#f3e5f5
    style f fill:#e8f5e8
    style g fill:#fff3e0
    style i fill:#ffebee
    style j fill:#fce4ec

13.2 执行顺序验证代码

@component
public class executionorderverifier {
    
    // 1. 静态代码块(类加载时执行)
    static {
        system.out.println("1. 静态代码块执行");
    }
    
    public executionorderverifier() {
        system.out.println("2. 构造函数执行");
    }
    
    @postconstruct
    public void postconstruct() {
        system.out.println("3. @postconstruct方法执行");
    }
}

@component
public class executionorderverifier2 implements initializingbean {
    
    @postconstruct
    public void postconstruct() {
        system.out.println("4. @postconstruct方法执行(第二个bean)");
    }
    
    @override
    public void afterpropertiesset() throws exception {
        system.out.println("5. initializingbean.afterpropertiesset执行");
    }
}

@configuration
public class executionorderconfig {
    
    @bean(initmethod = "initmethod")
    public orderdemobean orderdemobean() {
        system.out.println("6. @bean方法执行 - 创建bean实例");
        return new orderdemobean();
    }
    
    public static class orderdemobean {
        public void initmethod() {
            system.out.println("7. @bean initmethod执行");
        }
    }
}

@component
@order(1)
public class orderapplicationrunner implements applicationrunner {
    @override
    public void run(applicationarguments args) throws exception {
        system.out.println("8. applicationrunner执行 - order(1)");
    }
}

@component  
@order(2)
public class ordercommandlinerunner implements commandlinerunner {
    @override
    public void run(string... args) throws exception {
        system.out.println("9. commandlinerunner执行 - order(2)");
    }
}

@component
public class ordereventlistener {
    
    @eventlistener(contextrefreshedevent.class)
    public void oncontextrefreshed(contextrefreshedevent event) {
        system.out.println("10. contextrefreshedevent事件处理");
    }
    
    @eventlistener(applicationreadyevent.class)
    public void onapplicationready(applicationreadyevent event) {
        system.out.println("11. applicationreadyevent事件处理 - 应用完全就绪");
    }
}

14. 实际应用案例

14.1 完整的系统初始化器

@component
@order(1)
public class systeminitializer implements applicationrunner {
    
    private static final logger logger = loggerfactory.getlogger(systeminitializer.class);
    
    private final applicationcontext applicationcontext;
    private final datasource datasource;
    private final redistemplate<string, object> redistemplate;
    private final systemconfigrepository configrepository;
    
    public systeminitializer(applicationcontext applicationcontext,
                           datasource datasource,
                           redistemplate<string, object> redistemplate,
                           systemconfigrepository configrepository) {
        this.applicationcontext = applicationcontext;
        this.datasource = datasource;
        this.redistemplate = redistemplate;
        this.configrepository = configrepository;
    }
    
    @override
    public void run(applicationarguments args) throws exception {
        logger.info("====== 系统初始化开始 ======");
        
        // 阶段1: 基础设施检查
        checkinfrastructure();
        
        // 阶段2: 数据初始化
        initializedata();
        
        // 阶段3: 缓存预热
        warmupcaches();
        
        // 阶段4: 服务启动
        startservices();
        
        logger.info("====== 系统初始化完成 ======");
    }
    
    private void checkinfrastructure() {
        logger.info("阶段1: 检查基础设施...");
        
        // 检查数据库
        checkdatabase();
        
        // 检查redis
        checkredis();
        
        // 检查磁盘空间
        checkdiskspace();
        
        logger.info("基础设施检查完成");
    }
    
    private void checkdatabase() {
        try (connection connection = datasource.getconnection()) {
            databasemetadata metadata = connection.getmetadata();
            string dbname = metadata.getdatabaseproductname();
            string version = metadata.getdatabaseproductversion();
            logger.info("数据库连接正常: {} {}", dbname, version);
            
            // 检查必要的表是否存在
            checkrequiredtables(connection);
            
        } catch (sqlexception e) {
            logger.error("数据库检查失败", e);
            throw new runtimeexception("数据库不可用", e);
        }
    }
    
    private void checkrequiredtables(connection connection) throws sqlexception {
        string[] requiredtables = {"users", "system_config", "audit_log"};
        databasemetadata metadata = connection.getmetadata();
        
        for (string table : requiredtables) {
            try (resultset rs = metadata.gettables(null, null, table, null)) {
                if (!rs.next()) {
                    throw new runtimeexception("必要的表不存在: " + table);
                }
            }
        }
        logger.info("所有必要的表都存在");
    }
    
    private void checkredis() {
        try {
            redistemplate.opsforvalue().set("health-check", "ok", duration.ofseconds(10));
            string result = (string) redistemplate.opsforvalue().get("health-check");
            if ("ok".equals(result)) {
                logger.info("redis连接正常");
            } else {
                throw new runtimeexception("redis响应异常");
            }
        } catch (exception e) {
            logger.error("redis检查失败", e);
            throw new runtimeexception("redis不可用", e);
        }
    }
    
    private void checkdiskspace() {
        file root = new file("/");
        long freespace = root.getfreespace();
        long totalspace = root.gettotalspace();
        double freepercent = (double) freespace / totalspace * 100;
        
        logger.info("磁盘空间: {}/{} gb ({:.2f}% 空闲)",
            (totalspace - freespace) / (1024 * 1024 * 1024),
            totalspace / (1024 * 1024 * 1024),
            freepercent);
            
        if (freepercent < 10.0) {
            logger.warn("磁盘空间不足,空闲空间低于10%");
        }
    }
    
    private void initializedata() {
        logger.info("阶段2: 初始化数据...");
        
        // 加载系统配置
        loadsystemconfigs();
        
        // 初始化基础数据
        initializebasedata();
        
        logger.info("数据初始化完成");
    }
    
    private void loadsystemconfigs() {
        try {
            list<systemconfig> configs = configrepository.findall();
            logger.info("加载了 {} 条系统配置", configs.size());
            
            // 将配置加载到内存或缓存中
            configs.foreach(config -> {
                logger.debug("系统配置: {} = {}", config.getkey(), config.getvalue());
            });
            
        } catch (exception e) {
            logger.error("系统配置加载失败", e);
            throw new runtimeexception("系统配置加载失败", e);
        }
    }
    
    private void initializebasedata() {
        logger.info("初始化基础数据...");
        // 模拟基础数据初始化
        // 如:默认用户、角色、权限等
    }
    
    private void warmupcaches() {
        logger.info("阶段3: 缓存预热...");
        
        // 预热用户缓存
        warmupusercache();
        
        // 预热配置缓存
        warmupconfigcache();
        
        logger.info("缓存预热完成");
    }
    
    private void warmupusercache() {
        logger.info("预热用户缓存...");
        // 模拟用户缓存预热
    }
    
    private void warmupconfigcache() {
        logger.info("预热配置缓存...");
        // 模拟配置缓存预热
    }
    
    private void startservices() {
        logger.info("阶段4: 启动服务...");
        
        // 启动定时任务服务
        startscheduledtasks();
        
        // 启动消息监听服务
        startmessagelisteners();
        
        logger.info("服务启动完成");
    }
    
    private void startscheduledtasks() {
        logger.info("启动定时任务...");
        // 模拟定时任务启动
    }
    
    private void startmessagelisteners() {
        logger.info("启动消息监听器...");
        // 模拟消息监听器启动
    }
}

15. 最佳实践和注意事项

15.1 最佳实践

合理选择初始化方式

  • bean初始化使用 @postconstruct
  • 应用启动后任务使用 applicationrunner
  • 需要命令行参数的使用 commandlinerunner

控制初始化顺序

  • 使用 @order 注解控制多个 runner 的执行顺序
  • 理解不同初始化方式的执行时机

异常处理

  • 初始化失败应该快速失败
  • 提供清晰的错误信息
  • 区分关键初始化和非关键初始化

性能考虑

  • 避免在初始化阶段执行耗时操作
  • 长时间任务应该异步执行
  • 考虑使用懒加载

15.2 注意事项

  1. 避免循环依赖:在初始化阶段特别注意bean之间的依赖关系
  2. 配置验证:尽早验证配置的正确性
  3. 资源清理:对于需要清理的资源,实现相应的销毁方法
  4. 日志记录:详细记录初始化过程,便于问题排查

16. 总结

本文详细介绍了 spring boot 中 10 种在启动时执行特定代码的方式,涵盖了从简单的注解到复杂的事件监听等各种场景。每种方式都有其特定的使用场景和执行时机,在实际项目中应该根据具体需求选择合适的方式。

通过合理使用这些初始化机制,可以确保应用在启动时完成所有必要的准备工作,为应用的稳定运行奠定坚实的基础。

以上就是springboot启动时执行特定代码的10种方式的详细内容,更多关于springboot启动时执行特定代码的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com