【Spring】关于CommandLineRunner 和 SmartInitializingSingleton

昨天扯到了CommandLineRunner ,今天出来个SmartInitializingSingleton

CommandLineRunnerSmartInitializingSingleton 在Spring框架中都用于在应用程序启动后执行某些初始化逻辑,但它们的触发时机、使用场景和设计目的有很大的不同。下面以大白话的形式解释两者的区别:

CommandLineRunner

想象你正在筹备一个派对,派对还没开始,你就想先播放一些音乐来营造氛围。CommandLineRunner就像你派对开始前的DJ,它一上来就直接放音乐,不等人到齐。也就是说,CommandLineRunner在Spring应用完全启动后立即执行,它的主要任务是做一些启动后的初始化工作,比如打印一些信息到控制台,或者做一些简单的数据导入等。它不关心其他的Bean是否已经完全初始化,只要Spring容器已经启动,它就开始干活。

SmartInitializingSingleton

SmartInitializingSingleton更像是你派对上的总策划,他要等到所有的宾客都到场,一切都准备妥当之后,才开始他的工作。这意味着实现SmartInitializingSingleton接口的Bean会在所有单例Bean实例化完成后执行其afterSingletonsInstantiated()方法。它更适合那些需要在所有其他Bean都准备就绪之后才能进行的初始化逻辑,比如依赖于其他服务的状态检查、注册监听器等。

总结

  • 触发时机CommandLineRunner在所有Bean定义加载后立即执行,而SmartInitializingSingleton在所有单例Bean实例化完成后执行。
  • 依赖关系CommandLineRunner不依赖于其他Bean的初始化状态,而SmartInitializingSingleton可能依赖于其他Bean的状态。
  • 使用场景CommandLineRunner适用于那些需要在应用启动后立即执行的简单任务,而SmartInitializingSingleton适用于那些需要在所有服务Bean都准备就绪后执行的复杂初始化逻辑。

简单来说,CommandLineRunner是“派对刚开始就上场的DJ”,而SmartInitializingSingleton是“派对一切准备就绪后的总策划”。两者各有侧重,根据你的应用需求选择合适的一个或组合使用。

  • CommandLineRunner在容器启动后立即执行,此时单例Bean可能已经实例化,但不一定完全初始化,尤其是那些依赖于复杂初始化逻辑的Bean。
  • SmartInitializingSingleton则是在所有单例Bean实例化并且初始化完成之后执行,这意味着它依赖于所有其他单例Bean的状态。

使用场景示例:CommandLineRunner

CommandLineRunner接口通常用于执行一些简单的初始化任务,比如数据库的初始化、数据填充等,这些任务通常不需要依赖于其他Bean的完全初始化状态。下面是一个使用CommandLineRunner的示例:

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

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Application started, executing CommandLineRunner...");
        
        // 这里可以执行一些简单的初始化逻辑,例如数据填充
        // 注意:在多实例化环境(非单例)中,可能需要添加同步处理
        
        // 示例:填充数据库
        // userRepository.save(new User("John", "xxxxxx@example.com"));
        
        System.out.println("CommandLineRunner finished.");
    }
}

在这个示例中,MyCommandLineRunner实现了CommandLineRunner接口,它的run方法将在Spring容器启动后立即执行。注意,这个方法在Spring容器中所有单例Bean实例化之后,但在所有Bean完全初始化之前执行。

使用场景示例:SmartInitializingSingleton

SmartInitializingSingleton接口用于那些需要在所有单例Bean完全初始化之后才能执行初始化逻辑的场景。这通常涉及一些较为复杂的初始化任务,比如依赖于多个服务的集成或状态检查。下面是一个使用SmartInitializingSingleton的示例:

xxl-job源码中初始化执行器有这么一段

public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
    private static final Logger logger = LoggerFactory.getLogger(XxlJobSpringExecutor.class);


    // start
    @Override
    public void afterSingletonsInstantiated() {

        // init JobHandler Repository
        /*initJobHandlerRepository(applicationContext);*/

        // init JobHandler Repository (for method)
        initJobHandlerMethodRepository(applicationContext);

        // refresh GlueFactory
        GlueFactory.refreshInstance(1);

        // super start
        try {
            super.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

省略.......
}

调用了父类得start()方法

干了几件事

/ 初始化日志路径
XxlJobFileAppender.initLogPath(logPath);

// 创建调度器的客户端
initAdminBizList(adminAddresses, accessToken);

// 初始化日志清理线程
JobLogFileCleanThread.getInstance().start(logRetentionDays);

// 初始化Trigger回调线程
TriggerCallbackThread.getInstance().start();

// 初始化执行器服务器
initEmbedServer(address, ip, port, appname, accessToken);

这两个示例展示了CommandLineRunnerSmartInitializingSingleton的不同使用场景,前者适合简单的、不需要依赖其他Bean完全初始化的任务,后者适合较为复杂的、需要确保所有依赖都已经就绪的任务。

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值