Spring Boot 启动后执行器深度指南:CommandLineRunner vs ApplicationRunner

SpringBoot应用启动后自动退出:exit code 0问题深度解析与解决方案 在Java应用开发中,进程生命周期管理和线程模型是保障服务稳定运行的基础概念。SpringBoot框架通过内嵌Web容器(如Tomcat)的非守护线程来维持应用进程活跃,其核心原理在于JVM会在所有非守护线程结束时自动退出。这一机制对于构建高可用的Web服务和后台常驻进程具有重要技术价值,广泛应用于微服务、API接口和消息处理等场景。当应用依赖配置不当或主线程逻辑存在缺陷时,可能出现进程意外退出的情况,具体表现为控制台输出exit code 0。本文聚焦SpringBoot应用启动即关闭的典型问题,通过分析 阅读详情

以下是关于 Spring Boot 中 CommandLineRunner 与 ApplicationRunner 的完整深度解析文档,涵盖其定义、作用、执行时机、核心区别、与事件监听器的对比、实际应用场景,并提供工业级标准代码示例,所有示例均附带详尽中文注释,完全符合你对“实际开发参考价值”和“清晰注释”的要求。**


📜 Spring Boot 启动后执行器深度指南:CommandLineRunner vs ApplicationRunner

✅ 适用版本:Spring Boot 3.x + JDK 17+
✅ 核心目标:彻底厘清 CommandLineRunner 与 ApplicationRunner 的执行时机、参数处理、使用场景及与事件监听器的区别


一、什么是 CommandLineRunner 和 ApplicationRunner?

🔍 定义:

接口说明
CommandLineRunnerSpring Boot 提供的命令行参数执行接口,在 Spring 容器启动完成后、应用完全就绪前自动调用,接收原始字符串数组参数(即 main 方法传入的 args)
ApplicationRunnerSpring Boot 提供的增强型应用启动执行接口,在 Spring 容器启动完成后、应用完全就绪前自动调用,接收封装后的 ApplicationArguments 对象,支持参数类型解析(如选项、非选项参数)

✅ 二者都是Spring 管理的 Bean,需标注 @Component 或通过 @Bean 注册。


二、执行时机详解(生命周期定位)

🌲 Spring Boot 启动流程关键节点(按顺序):

graph LR
    A[main() 方法执行] --> B[SpringApplication.run()]
    B --> C[SpringApplicationRunListener.starting()]
    C --> D[SpringApplicationRunListener.environmentPrepared()]
    D --> E[ApplicationContext 创建]
    E --> F[Bean 加载]
    F --> G[ApplicationContext.refresh()]
    G --> H[ApplicationRunner / CommandLineRunner 执行]
    H --> I[ApplicationReadyEvent 发布]
    I --> J[应用对外提供服务]

✅ 执行时机结论:

组件执行时机是否在应用就绪前?是否可访问所有 Bean?
CommandLineRunnerApplicationContext.refresh() 完成后,ApplicationReadyEvent 发布前✅ 是✅ 是
ApplicationRunner同上,紧随 CommandLineRunner✅ 是✅ 是
ApplicationReadyEvent在 ApplicationRunner 和 CommandLineRunner 之后❌ 否(应用已就绪)✅ 是

⚠️ 重要:
CommandLineRunner 和 ApplicationRunner 都在应用“可对外提供 HTTP 服务”之前执行。
也就是说,此时 Web 服务器(如 Tomcat)尚未绑定端口,但所有 Spring Bean 已加载完毕,可以安全注入 @Autowired 服务、RedisTemplate、JdbcTemplate 等。


三、CommandLineRunner 与 ApplicationRunner 的核心区别

维度CommandLineRunnerApplicationRunner
参数类型String[] args(原始命令行参数)ApplicationArguments(封装对象)
参数解析能力❌ 无内置解析,需手动处理✅ 自动解析:getOptionNames()、getNonOptionArgs()
参数格式支持仅支持 --key=value、arg1 arg2 等原始字符串✅ 支持 --key=value、--key value、-k value 等标准格式
是否推荐使用⚠️ 旧式,不推荐新项目✅ 推荐,功能更强、更安全
异常处理抛出异常会终止应用启动抛出异常会终止应用启动
执行顺序默认优先于 ApplicationRunner默认在 CommandLineRunner 之后
可排序✅ 支持 @Order✅ 支持 @Order
是否支持类型转换❌ 不支持✅ 支持(如 --timeout=30s → Duration)
使用场景简单脚本、旧项目维护现代应用、生产环境、复杂参数

✅ 官方建议:
Spring 官方文档推荐使用 ApplicationRunner,因为它提供了更健壮、更规范的参数处理机制。


四、与事件监听器(ApplicationListener / @EventListener)的区别

维度CommandLineRunner / ApplicationRunnerApplicationListener / @EventListener
触发时机应用启动后、服务就绪前(单次执行)可在启动后任意阶段触发(可多次)
执行次数✅ 仅执行一次✅ 可多次(如 ContextRefreshedEvent 可触发多次)
是否依赖事件❌ 不依赖事件,是独立钩子✅ 依赖事件发布(如 ApplicationReadyEvent)
是否可中断启动✅ 抛异常可中断✅ 抛异常可中断(但需注意是否被 @Async 包裹)
是否支持参数✅ 支持命令行参数❌ 不支持(除非事件携带参数)
是否适合初始化✅ 强烈推荐用于初始化✅ 推荐用于解耦业务响应
典型用途数据初始化、缓存预热、脚本执行发邮件、发通知、异步任务、日志记录
能否注入 Bean✅ 可以✅ 可以
是否异步❌ 同步阻塞✅ 可通过 @Async 实现异步

✅ 一句话总结:

  • CommandLineRunner / ApplicationRunner 是“启动后执行一次的初始化脚本”
  • @EventListener 是“事件驱动的响应式处理器”

五、标准实战示例(带详细中文注释)

✅ 场景:系统启动后自动初始化数据库、预热缓存、打印启动报告

🎯 目标:
  • 从命令行传入环境参数:--env=prod --timeout=30s
  • 初始化数据库表结构
  • 预热 Redis 缓存
  • 打印启动报告(包含启动耗时、端口、环境)

步骤 1:实现 ApplicationRunner(推荐方式)

package com.example.demo.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 应用启动后执行器:使用 ApplicationRunner(推荐)
 * 作用:在应用完全启动前,执行初始化逻辑
 * 特点:支持参数解析、可注入 Spring Bean、可排序
 */
@Component
@Order(1) // 设置优先级,数字越小越先执行
public class ApplicationInitRunner implements ApplicationRunner {

    private static final Logger log = LoggerFactory.getLogger(ApplicationInitRunner.class);

    @Autowired
    private StringRedisTemplate redisTemplate; // ✅ 可注入,Redis 已就绪

    @Autowired
    private DataSource dataSource; // ✅ 可注入,数据库连接池已创建

    @Resource
    private RabbitTemplate rabbitTemplate; // ✅ 可注入,消息队列已连接

    /**
     * Spring Boot 在 ApplicationContext 刷新完成后,自动调用此方法
     * 此时所有 Bean 已加载,但 Web 服务器尚未绑定端口(如 Tomcat 未启动)
     * 可安全执行数据库初始化、缓存预热、配置校验等
     *
     * @param args 封装后的命令行参数对象,支持选项与非选项参数解析
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("🚀 [ApplicationRunner] 开始执行应用初始化逻辑...");

        // 1. 解析命令行参数
        String env = getEnvFromArgs(args); // 获取 --env=prod
        Duration timeout = getTimeoutFromArgs(args); // 获取 --timeout=30s

        log.info("⚙️ 应用环境: {}", env);
        log.info("⏱️ 服务超时时间: {}", timeout);

        // 2. 检查数据库连接(模拟)
        try (var conn = dataSource.getConnection()) {
            if (conn.isValid(5)) {
                log.info("✅ 数据库连接正常");
            } else {
                throw new IllegalStateException("❌ 数据库连接失败,应用终止");
            }
        }

        // 3. 初始化数据库表结构(模拟)
        initDatabaseSchema();

        // 4. 预热 Redis 缓存(如系统字典)
        warmupRedisCache();

        // 5. 发送启动通知到消息队列(可选)
        sendStartupNotification(env);

        // 6. 打印启动报告
        printStartupReport(env, timeout);

        log.info("🎉 [ApplicationRunner] 应用初始化完成,即将启动 Web 服务...");
    }

    // ==================== 辅助方法 ====================

    /**
     * 从 ApplicationArguments 中获取 --env 参数值
     * 支持格式:--env=prod、--env prod、-e prod
     *
     * @param args ApplicationArguments 对象
     * @return 环境名,如 "prod",若未设置返回 "dev"
     */
    private String getEnvFromArgs(ApplicationArguments args) {
        if (args.containsOption("env")) {
            List<String> values = args.getOptionValues("env");
            return values != null && !values.isEmpty() ? values.get(0) : "dev";
        }
        return "dev"; // 默认值
    }

    /**
     * 从 ApplicationArguments 中获取 --timeout 参数(自动转换为 Duration 类型)
     * 支持格式:--timeout=30s、--timeout=1m、--timeout=30000ms
     *
     * @param args ApplicationArguments 对象
     * @return Duration 对象,如 30 秒
     */
    private Duration getTimeoutFromArgs(ApplicationArguments args) {
        if (args.containsOption("timeout")) {
            List<String> values = args.getOptionValues("timeout");
            if (values != null && !values.isEmpty()) {
                try {
                    return Duration.parse(values.get(0)); // Spring 自动支持 ISO 8601 格式
                } catch (Exception e) {
                    log.warn("⚠️ 无法解析 timeout 参数: {}", values.get(0));
                }
            }
        }
        return Duration.ofSeconds(10); // 默认 10 秒
    }

    /**
     * 模拟初始化数据库表结构
     */
    private void initDatabaseSchema() {
        log.info("💾 正在初始化数据库表结构...");
        // 模拟执行 SQL:CREATE TABLE IF NOT EXISTS user ...
        // 实际项目中使用 Flyway / Liquibase 更规范
        try {
            Thread.sleep(1000); // 模拟耗时
            log.info("✅ 数据库表结构初始化完成");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("❌ 数据库初始化被中断", e);
        }
    }

    /**
     * 预热 Redis 缓存:加载系统字典
     */
    private void warmupRedisCache() {
        log.info("🔄 正在预热 Redis 缓存...");
        String[] keys = {"system:dict:region", "system:dict:user_status", "system:dict:order_status"};
        String[] values = {"北京市,上海市", "激活,冻结", "待支付,已发货"};

        for (int i = 0; i < keys.length; i++) {
            redisTemplate.opsForValue().set(keys[i], values[i], 24, java.util.concurrent.TimeUnit.HOURS);
            log.info("💾 缓存键: {} = {}", keys[i], values[i]);
        }
        log.info("✅ Redis 缓存预热完成");
    }

    /**
     * 发送启动通知到 RabbitMQ
     */
    private void sendStartupNotification(String env) {
        log.info("📩 正在发送启动通知到消息队列...");
        String message = "系统已启动,环境=" + env + ",时间=" + LocalDateTime.now();
        rabbitTemplate.convertAndSend("system.logs", "startup", message);
        log.info("✅ 启动通知已发送至 RabbitMQ");
    }

    /**
     * 打印启动报告
     */
    private void printStartupReport(String env, Duration timeout) {
        log.info("\n" +
                "=============================================\n" +
                "          🚀 应用启动报告\n" +
                "=============================================\n" +
                "环境: {}\n" +
                "启动时间: {}\n" +
                "超时配置: {}\n" +
                "Redis 连接: 已预热\n" +
                "数据库: 已初始化\n" +
                "=============================================\n",
                env,
                LocalDateTime.now(),
                timeout
        );
    }
}

步骤 2:实现 CommandLineRunner(旧式写法,仅作对比)

package com.example.demo.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

/**
 * 命令行执行器:使用 CommandLineRunner(旧式,不推荐)
 * 作用:接收原始命令行参数数组,执行初始化
 * 缺点:需要手动解析参数,无类型安全,易出错
 */
@Component
@Order(2) // 设置优先级,确保在 ApplicationRunner 之后执行
public class LegacyInitRunner implements CommandLineRunner {

    private static final Logger log = LoggerFactory.getLogger(LegacyInitRunner.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * Spring Boot 在启动后调用此方法,传入原始 args 数组
     * 注意:必须手动解析参数,如 "--env=prod"、"start"、"stop"
     *
     * @param args 原始命令行参数数组,如 ["--env=prod", "--timeout=30s", "start"]
     */
    @Override
    public void run(String... args) throws Exception {
        log.info("🔧 [CommandLineRunner] 开始执行初始化(旧式方式)...");

        // 手动解析参数(易错、难维护)
        String env = "dev";
        boolean shouldStart = true;

        for (String arg : args) {
            if (arg.startsWith("--env=")) {
                env = arg.substring("--env=".length());
            } else if ("--no-start".equals(arg)) {
                shouldStart = false;
            }
        }

        log.info("⚙️ 解析环境: {}", env);
        log.info("⚙️ 是否启动服务: {}", shouldStart);

        // 模拟缓存预热
        redisTemplate.opsForValue().set("legacy:env", env);

        if (!shouldStart) {
            log.warn("🛑 用户指定不启动服务,但此方式无法阻止应用启动!");
            // ❌ 无法阻止应用启动,只能记录
        }

        log.info("✅ [CommandLineRunner] 初始化完成");
    }
}

⚠️ 问题:

  • 无法优雅处理 --timeout=30s → 必须手动解析字符串
  • 无法区分 --key value 和 --key=value
  • 无法使用 Duration、LocalDateTime 等类型安全参数
  • 无法阻止应用启动(即使发现错误,也只能记录)

步骤 3:测试启动(命令行传参)

✅ 启动命令:
java -jar your-app.jar --env=prod --timeout=30s --no-start
✅ 控制台输出(示例):
🚀 [ApplicationRunner] 开始执行应用初始化逻辑...
⚙️ 应用环境: prod
⏱️ 服务超时时间: PT30S
✅ 数据库连接正常
💾 正在初始化数据库表结构...
✅ 数据库表结构初始化完成
🔄 正在预热 Redis 缓存...
💾 缓存键: system:dict:region = 北京市,上海市
💾 缓存键: system:dict:user_status = 激活,冻结
💾 缓存键: system:dict:order_status = 待支付,已发货
✅ Redis 缓存预热完成
📩 正在发送启动通知到消息队列...
✅ 启动通知已发送至 RabbitMQ

=============================================
          🚀 应用启动报告
=============================================
环境: prod
启动时间: 2025-10-14T10:30:00
超时配置: PT30S
Redis 连接: 已预热
数据库: 已初始化
=============================================

🎉 [ApplicationRunner] 应用初始化完成,即将启动 Web 服务...

🔧 [CommandLineRunner] 开始执行初始化(旧式方式)...
⚙️ 解析环境: prod
⚙️ 是否启动服务: false
✅ [CommandLineRunner] 初始化完成

✅ 注意:

  • ApplicationRunner 先执行(@Order(1))
  • CommandLineRunner 后执行(@Order(2))
  • --no-start 被 CommandLineRunner 解析,但无法阻止应用启动,仅作记录

六、实际应用场景对比表

场景推荐使用说明
初始化数据库表结构✅ ApplicationRunner需要注入 JdbcTemplate,必须在 Web 服务启动前完成
预热 Redis 缓存✅ ApplicationRunner需要 RedisTemplate,且必须在首次请求前完成
加载系统字典到内存✅ ApplicationRunner依赖数据库连接,需注入服务
从命令行启动时指定环境✅ ApplicationRunner支持 --env=prod、--timeout=30s 等类型安全参数
启动后自动执行脚本(如数据迁移)✅ ApplicationRunner可配合 @Profile("prod") 仅在生产环境执行
打印启动日志/报告✅ ApplicationRunner可注入 Environment 获取端口、版本等信息
仅需简单传参(如 --debug)⚠️ CommandLineRunner仅限简单场景,新项目不推荐
阻止应用启动(如配置缺失)❌ 两者均无法阻止若需阻止,应使用 SpringApplicationRunListener + environmentPrepared 抛异常

✅ 最佳实践:

  • 新项目一律使用 ApplicationRunner
  • 旧项目逐步替换 CommandLineRunner
  • 禁止在 CommandLineRunner 中做复杂参数解析

七、如何阻止应用启动?

❗ ApplicationRunner 和 CommandLineRunner 不能阻止应用启动,即使抛出异常,也仅终止当前执行,应用仍会继续启动。

✅ 正确做法:使用 SpringApplicationRunListener

// 在 environmentPrepared 中抛异常,强制终止
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
    if (System.getenv("DB_PASSWORD") == null) {
        throw new IllegalStateException("❌ 数据库密码未配置,应用终止启动");
    }
}

✅ 结论:

  • 初始化失败 → 用 SpringApplicationRunListener
  • 初始化成功 → 用 ApplicationRunner

八、与事件监听器的协作建议

场景使用 ApplicationRunner使用 ApplicationListener
启动后初始化数据库、缓存✅ 推荐❌ 不推荐(事件可能多次触发)
用户注册后发邮件❌ 不适用✅ 推荐
应用启动后记录监控指标✅ 推荐✅ 也可用(但需监听 ApplicationReadyEvent)
启动后触发定时任务✅ 推荐(启动时注册)✅ 推荐(监听 ApplicationReadyEvent)

✅ 推荐组合:

@Component
public class StartupInitializer implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) {
        // 1. 初始化数据库、缓存、连接池
        initSystem();
        
        // 2. 注册定时任务
        scheduler.schedule(task, cron);
        
        // 3. 发布自定义事件,通知其他模块
        eventPublisher.publishEvent(new SystemInitializedEvent(this));
    }
}

九、总结:开发者必须掌握的决策指南

问题推荐方案
我想在应用启动后、服务对外前,执行初始化逻辑(如缓存、数据库)✅ 使用 ApplicationRunner
我想从命令行传入 --env=prod --timeout=30s 并自动解析✅ 使用 ApplicationRunner
我想在启动失败时阻止应用启动✅ 使用 SpringApplicationRunListener 抛异常
我想在用户注册后发邮件✅ 使用 @EventListener(UserRegisteredEvent.class)
我想打印启动报告(包含端口、版本、环境)✅ 使用 ApplicationRunner + Environment
我想执行一次性脚本(如数据迁移)✅ 使用 ApplicationRunner + @Profile("prod")
我还在用 CommandLineRunner 解析 --key=value⚠️ 立即替换为 ApplicationRunner

✅ 最终建议(黄金法则)

原则说明
✅ 新项目一律使用 ApplicationRunner更安全、更规范、支持类型安全、官方推荐
✅ 避免使用 CommandLineRunner除非维护遗留系统,否则不要在新项目中使用
✅ 初始化失败用 SpringApplicationRunListener它是唯一能阻止启动的机制
✅ 业务响应用 @EventListener解耦、异步、可重用
✅ 启动报告用 ApplicationRunner可访问 Environment、ApplicationContext、Logger
✅ 不要在 ApplicationRunner 中做耗时操作会阻塞 Web 服务启动,建议异步化(如 @Async)

💡 进阶建议:
若你希望在启动后异步执行初始化(不阻塞 Web 服务启动),可在 ApplicationRunner 中启动一个线程:

@Override
public void run(ApplicationArguments args) {
    new Thread(() -> {
        try {
            Thread.sleep(5000); // 模拟耗时
            log.info("⏳ 异步初始化完成");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }).start();
}

但注意:主线程仍会继续启动 Web 服务,适合“后台任务”而非“核心初始化”。


Spring Boot整合Redis认证失败:NOAUTH异常排查与解决方案 在分布式系统架构中,缓存作为提升应用性能的核心组件,其安全认证机制是保障数据安全的重要环节。Redis作为主流的内存数据库,通过密码认证和ACL(访问控制列表)实现访问控制。当客户端与服务器建立连接时,需通过AUTH命令完成身份验证,其原理基于TCP连接会话的状态管理。这一机制的技术价值在于防止未授权访问,确保缓存数据在微服务、会话存储等应用场景中的安全性。实践中,Spring Boot应用通过Lettuce客户端连接Redis时,常因配置错误、连接池失效或拓扑模式(如哨兵、集群)的复杂认证导致NOAUTH 阅读详情

相关推荐

技术博客创作方法论:从选题到实战,解决内容枯竭难题

技术内容创作是开发者知识沉淀与分享的重要方式,其核心在于将实践经验转化为结构化、可复现的知识体系。从原理层面看,有效的技术分享需要遵循从概念到实践的认知路径,通过系统化选题挖掘日常开发中的价值点,如Spring Boot集成、Redis缓存等常见场景。在工程实践中,这不仅能够帮助开发者深化对技术栈的理解,还能通过复盘决策过程、拆解源码实现来构建个人技术品牌。以缓存预热为例,结合ApplicationRunner与RedisTemplate的实战演示,展现了如何将通用技术方案转化为具体、可操作的博客内容,从而

weixin_33806300的博客 367

Spring Boot与Redis分布式缓存面试全解析

分布式缓存是解决高并发场景下系统性能瓶颈的关键技术,其核心原理是通过内存存储高频访问数据减少数据库压力。Redis作为主流内存数据库,支持丰富的数据结构如String、Hash、List等,配合Spring Boot的缓存抽象能实现多级缓存架构。在工程实践中,需要解决缓存穿透、雪崩、击穿等典型问题,常用方案包括布隆过滤器、差异化过期时间和分布式锁。互联网大厂面试常考察Spring Boot自动配置机制与Redis的深度整合,涉及@Cacheable注解原理、Redisson分布式锁实现等实战场景。掌握这些技

weixin_30550081的博客 360

(nginx) nginx5 nginx https部署实战

综上所述,相比 HTTP 协议,HTTPS 协议增加了很多握手、加密解密等流程,虽然过程很复杂,但其可以保证数据传输的安全。所以在这个互联网膨胀的时代,其中隐藏着各种看不见的危机,为了保证数据的安全,维护网络稳定,建议大家多多推广HTTPS。SSL 证书费用很高,以及其在服务器上的部署、更新维护非常繁琐HTTPS 降低用户访问速度(多次握手)网站改用HTTPS 以后,由HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用302跳转)

weixin_50382197的博客 1504

CommandLineRunner和ApplicationRunner

本文主要来自:https://blog.youkuaiyun.com/zongzhankui/article/details/78681942 &amp;nbsp; 前言: Spring Boot如何解决项目启动时初始化资源,在我们实际工作中,总会遇到这样需求,在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等。 为了达到这个目的,我们需要使用CommandLineRunner或Appli...

小强签名设计 的博客 2万+

群晖存储空间损毁不等于硬盘损坏:排查与修复实战

NAS存储系统中,物理硬盘、存储池与文件系统空间构成层级结构,任何一层出现异常都可能在管理界面汇总为“存储空间损毁”。事实上,异常断电、卷未正常挂载等软性问题也会触发这一红色告警,而存储池和硬盘SMART状态往往完全正常。理解这一机制后,用户无需急于格式化重建,通过事件日志审查、SSH确认挂载状态,再借助btrfs scrub等文件系统自愈工具,即可在数据不丢失的前提下恢复存储空间正常。该方案对家庭及小型办公环境中的群晖NAS尤其适用,特别是在供电不稳或硬盘休眠频繁的场景下,能有效规避误判风险。本文完整记录

weixin_30843121的博客 260

多普勒效应及多普勒频移的简单推导

多普勒频移的简单推导

m0_47867419的博客 3万+

CommandLineRunner、ApplicationRunner作用及区别

CommandLineRunner、ApplicationRunner是SpringBoot提供的接口(以下简称Runner接口),在SpringApplication.run()方法最后一步调用Runner接口的实现类,此时SpringBoot自身的初始化工作已完成,Runner接口是为自定义初始化任务提供的。那Runner接口有什么应用场景、区别是什么? 在我们实际工作中,总会遇到这样需求,在项目启动的时候需要做一些初始化的操作,比如初始化线程池,提前加载好加密证书等。...

zhangxuqqq的博客 4536

NSGA-III相关笔记

NSGA-III目录目的区别NSGA-III的算法流程非支配排序详解归一化详解 目录 NSGA-III基于matlab的实现 参考文献 1.An Evolutionary Many-Objective Optimization Algorithm Using Reference-point Based Non-dominated Sorting Approach,Part I: Solving P...

weixin_42555400的博客 1万+

CommandLineRunner与ApplicationRunner的介绍

原文链接地址:https://www.php.cn/java-article-416423.html 参考链接:https://www.cnblogs.com/myblogs-miller/p/9046425.html CommandLineRunner和ApplicationRunner是Spring Boot所提供的接口,他们都有一个run()方法。所有实现他们的Bean都会在Spring Boot服务启动之后自动地被调用。 由于这个特性,它们是一个理想地方去做一些初始化的工作,或者写一些测试代码

liuxiangke0210的专栏 1354

【阿里云大模型高级工程师ACP习题集】2.7 通过微调增强模型能力 (上篇)(⭐️⭐️⭐️ 重点章节!!!)

【摘要】这是我精心整理出对应的习题集,里面足足有 30 道题目,从基础概念到深度拓展,全方位覆盖章节重点、难点。不管你是想检验自己的学习成果,还是想针对薄弱环节进行强化训练,它都能完美适配!

davidkorhenn的博客 1603

Pre-suite 开发之MFi功能搭建

Pre-suite 固件中只有带无线硬件的Ezairo 7160sl才具备无线通信能力,其无线功能包括标准BLE 5.2 低功耗蓝牙功能以及非标准的低功耗无线音频流功能。Ezairo 7160sl 支持3种低功耗无线音频流协议:来自APPLE的MFi,来自Google的ASHA以及来自onsemi的remote mic。其中MFi音频流走的G.722编码的Mode1,速率为64kbps;而非MFi音频流走的G.722的Mode3,速率为48kbps.

SnowYang2017的博客 1497

详解ApplicationRunner和CommandLineRunner

一文详解ApplicationRunner和CommandLineRunner

卓越之识论道,平常之识论事,狭隘之识论人 1984

apache 403错误 Forbidden解决方法

当网页打开提示以下错误时,即出现了403错误。 Forbidden You don't have permission to access / on this server. 403 Forbidden 资源不可用。服务器理解客户的请求,但拒绝处理它。通常由于服务器上文件或目录的权限设置导致。通常情况可能(但不限于此)的原因有: 原因1:apache配置文件中没有对站点目录的权限许可,这通...

lmseo5hy的博客 1493

解析Spring Boot中的CommandLineRunner和ApplicationRunner:用法、区别和适用场景详解

在Spring Boot应用程序中,CommandLineRunner和ApplicationRunner是两个重要的接口,它们允许我们在应用程序启动后执行一些初始化任务。本文将介绍CommandLineRunner和ApplicationRunner的区别,并提供代码示例和使用场景,让我们更好地理解和使用这两个接口。

Apple_Boy的博客 4635

【Proteus仿真】点亮小灯系列仿真——小灯闪烁/流水灯/交通灯

本文介绍了基于AT89C51单片机的LED控制案例,共包含5个实例:1)单个LED闪烁;2)共阳极流水灯;3)共阴极流水灯;4)花样流水灯;5)交通灯模拟。每个案例详细说明了电路原理图、接线方式和控制程序实现,其中重点讲解了PWM调光原理及其在LED控制中的应用。案例由简至繁,从基础I/O控制到复杂花样显示,最后实现交通灯逻辑控制,展示了单片机在LED控制中的典型应用方法。文中提供了完整的源代码,便于读者理解和实践。

XU157303764的博客 1882

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Java面试必备:Spring Boot与微服务架构深度解析

Spring Boot作为Java生态中的主流开发框架,通过自动配置和Starter依赖等机制显著提升了开发效率。其底层基于Spring框架的IoC容器和条件注解系统,实现了约定优于配置的核心理念。微服务架构则是分布式系统设计的重要范式,涉及服务拆分、通信协议、服务治理等关键技术点。在云原生时代,Spring Boot与微服务架构的组合已成为企业级应用开发的事实标准,特别是在电商、金融等需要高并发、高可用的场景中。理解Spring Boot的自动配置原理和微服务的服务治理机制,不仅能帮助开发者应对技术面试,

weixin_34025051的博客 417

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Java面试核心:Spring Boot、微服务与Redis实战解析

在当今的Java技术栈中,Spring Boot、微服务架构和Redis已成为开发者必须掌握的核心技术。Spring Boot通过自动配置机制简化了传统Spring应用的开发流程,其底层原理涉及条件注解和starter机制,大幅提升了开发效率。微服务架构解决了单体应用的可扩展性问题,通过服务注册发现、配置中心和服务网关实现分布式系统治理,其中分布式事务和熔断限流是保障系统稳定性的关键技术。Redis作为高性能内存数据库,其底层数据结构和分布式锁实现原理是面试高频考点,合理运用多级缓存架构能显著提升系统性能。

weixin_33912638的博客 410

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Spring Boot高级特性实战:从自动装配到生产级应用部署

Spring Boot作为Java领域主流的微服务框架,其核心价值在于通过自动装配机制实现了约定大于配置的开发理念。理解其自动装配原理,掌握条件化装配与自定义Starter开发,是构建可复用组件和解决Bean冲突的关键。在生产环境中,配置管理、优雅停机和健康检查是保障应用稳定性的基础技术。面对大文件上传、分布式事务等复杂场景,需要结合流式处理与柔性事务方案来确保系统性能与数据一致性。本文聚焦Spring Boot高级应用,深入探讨自动装配、生产部署优化及分布式事务处理等核心实践,帮助开发者构建健壮高效的企业

weixin_34234829的博客 314

Spring Boot 2026 核心知识点全解:自动配置原理 + 实战代码 + 微服务整合

Spring Boot 是Pivotal 团队于 2013 年开始研发、2014 年 4 月正式发布第一个版本的Spring 框架快速开发工具。它不是对 Spring 框架的替代,而是基于 Spring 框架的“脚手架”级增强。其最核心的设计哲学是“约定优于配置”机制作用自动配置(Auto-Configuration)根据类路径中的依赖自动配置 Spring Bean起步依赖(Starter)聚合依赖包,一处引入、全家可用嵌入式服务器(Embedded Server)

2303_77980993的博客 243

RMI Registry启动时序陷阱:1099端口连接失败的根源与解法

RMI Registry是Java分布式通信中用于服务注册与发现的核心组件,其本质是基于TCP的远程对象绑定服务,并非JVM默认启动项。它依赖显式调用LocateRegistry.createRegistry()或rmiregistry命令初始化,存在典型启动延迟(120–350ms),导致客户端JNDI lookup因‘连接拒绝’而失败。该问题常被误判为网络层ping异常,实则源于JVM服务生命周期与Spring Bean初始化顺序间的竞态条件。技术价值在于厘清RMI协议栈中Registry的懒加载机制与

weixin_34301132的博客 243

Spring Boot面试核心:从自动装配原理到项目部署实战

Spring Boot作为现代Java企业级开发的事实标准,其核心价值在于通过‘约定大于配置’和‘自动装配’两大设计哲学,极大地简化了应用开发与部署流程。自动装配机制基于条件注解实现按需加载,而Starter机制则通过依赖聚合解决了版本冲突与依赖冗余问题,共同构成了Spring Boot高效开发的基石。在工程实践中,这些特性使得开发者能够快速构建独立运行、生产就绪的微服务应用,广泛应用于从初创项目到大型分布式系统的后端服务搭建。本文聚焦于Spring Boot面试中的核心考察点,深入剖析自动装配原理与Sta

aizexi2652的博客 318

Java大厂面试必备:Spring Boot、微服务与AI整合实战

Spring Boot作为Java开发的主流框架,通过自动配置机制简化了传统Spring应用的搭建过程,其核心原理包括条件注解和starter依赖管理。微服务架构解决了单体应用的可扩展性问题,采用Spring Cloud等技术栈实现服务治理。AI技术如RAG架构和Agent开发正快速融入Java生态,Spring AI框架提供了统一的多模型API。这些技术的组合应用,尤其在互联网大厂面试中,成为评估Java开发者工程能力的重要标准。掌握Spring Boot的自动配置原理、微服务的分布式事务处理,以及AI技

weixin_34166472的博客 406

SpringApplication启动失败根因分析与排障指南

SpringApplication是Spring Boot应用的启动核心,其异常往往源于JVM类加载机制、依赖冲突或环境不兼容等底层问题。理解NoClassDefFoundError与ClassNotFoundException的本质区别、掌握JDK字节码版本与Spring Boot的兼容性约束、识别provided scope对fat-jar的影响,是解决启动失败的关键技术基础。通过mvn dependency:tree -Dverbose、java -verbose:class、jdeps等工具可精准定

weixin_34310369的博客 338

Spring Boot 3.x Jakarta迁移:解决index.html 404与getHttpServletMapping异常

Servlet 是 Java Web 的核心规范,其从 Java EE 8 到 Jakarta EE 9 的包名迁移(javax.* → jakarta.*)引发了二进制不兼容的系统性断层。这一变更导致 Spring Boot 3.x 默认无法加载 index.html、抛出 getHttpServletMapping 方法缺失或 ClassCastException 等典型错误。其技术本质是类加载器冲突与 API 签名断裂,而非配置或路径问题。该迁移带来显著工程价值:推动生态摆脱厂商锁定、支持云原生演进与

weixin_34335458的博客 403

SpringBoot面试宝典:44道核心题深度解析与实战指南

SpringBoot作为Java后端开发的主流框架,其核心设计理念是“约定大于配置”,通过自动配置机制简化了传统Spring应用的繁琐配置。理解其自动配置原理,关键在于掌握@SpringBootApplication注解及其背后的条件注解机制,如@ConditionalOnClass和@ConditionalOnMissingBean,这些机制使得框架能够根据类路径和容器状态智能装配Bean。这一特性极大地提升了开发效率,降低了项目启动和维护成本,是现代微服务架构和云原生应用的基础。在实际工程实践中,Spr

weixin_30411819的博客 362

Spring Bean生命周期详解:从实例化到销毁的完整流程

Bean生命周期是Spring框架的核心机制之一,指Bean从定义注册、实例化、属性注入、初始化回调,到最终销毁的全过程。其本质是一套分阶段、可插拔的容器编排模型,依赖BeanDefinition、BeanFactory及多种回调接口(如@PostConstruct、InitializingBean、BeanPostProcessor)协同工作。理解该机制对解决循环依赖、初始化失败、作用域异常等高频问题至关重要,也是实现AOP代理、性能监控、资源预热等工程实践的基础。本文基于Spring Boot 3.2+

weixin_30883311的博客 340
上一篇: Spring Boot 监听器深度对比:SpringApplicationRunListener vs ApplicationListener / @EventListener
下一篇: 标准 Git 分支管理策略(Git Flow)—— Java 后端开发实战指南
龙茶清欢
博客等级 码龄7年 3720粉丝 375原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙茶清欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值