搜索
首页Javajava教程springboot应用服务启动事件的监听怎么实现

    一、简介

    Spring Boot提供了两个接口:CommandLineRunner、ApplicationRunner,用于启动应用时做特殊处理,这些代码会在SpringApplication的run()方法运行完成之前被执行。相对于之前章节为大家介绍的Spring的ApplicationListener接口自定义监听器、Servlet的ServletContextListener监听器。使用二者的好处在于,可以方便的使用应用启动参数,根据参数不同做不同的初始化操作。

    二、常用场景介绍

    实现CommandLineRunner和ApplicationRunner接口。通常用于应用启动前的特殊代码执行,比如:

    • 将系统常用的数据加载到内存

    • 应用上一次运行的垃圾数据清理

    • 系统启动成功后的通知的发送等

    我通过实现CommandLineRunner接口,在应用启动时加载了系统内常用的配置数据,如下图所示。从数据库加载到内存,以后使用该数据的时候只需要调用getSysConfigList方法,不需要每次使用该数据都去数据库加载。节省系统资源、缩减数据加载时间。

    springboot应用服务启动事件的监听怎么实现

    二、代码小实验 通过@Component定义方式实现

    CommandLineRunner:参数是字符串数组

    @Slf4j
    @Component
    public class CommandLineStartupRunner implements CommandLineRunner {
        @Override
        public void run(String... args){
            log.info("CommandLineRunner传入参数:{}", Arrays.toString(args));
        }
    }

    ApplicationRunner:参数被放入ApplicationArguments,通过getOptionNames()、getOptionValues()、getSourceArgs()获取参数

    @Slf4j
    @Component
    public class AppStartupRunner implements ApplicationRunner {
        @Override
        public void run(ApplicationArguments args)  {
            log.info("ApplicationRunner参数名称: {}", args.getOptionNames());
            log.info("ApplicationRunner参数值: {}", args.getOptionValues("age"));
            log.info("ApplicationRunner参数: {}", Arrays.toString(args.getSourceArgs()));
        }
    }

    通过@Bean定义方式实现

    这种方式可以指定执行顺序,注意前两个Bean是CommandLineRunner,最后一个Bean是ApplicationRunner 。

    @Configuration
    public class BeanRunner {
        @Bean
        @Order(1)
        public CommandLineRunner runner1(){
            return new CommandLineRunner() {
                @Override
                public void run(String... args){
                    System.out.println("BeanCommandLineRunner run1()" + Arrays.toString(args));
                }
            };
        }
    
        @Bean
        @Order(2)
        public CommandLineRunner runner2(){
            return new CommandLineRunner() {
                @Override
                public void run(String... args){
                    System.out.println("BeanCommandLineRunner run2()" + Arrays.toString(args));
                }
            };
        }
    
        @Bean
        @Order(3)
        public ApplicationRunner runner3(){
            return new ApplicationRunner() {
                @Override
                public void run(ApplicationArguments args){
                    System.out.println("BeanApplicationRunner run3()" + Arrays.toString(args.getSourceArgs()));
                }
            };
        }
    }

    可以通过@Order设置执行顺序

    三、执行测试

    在IDEA Springboot启动配置中加入如下参数,保存后启动应用

    springboot应用服务启动事件的监听怎么实现

    测试输出结果:

    c.z.boot.launch.config.AppStartupRunner  : ApplicationRunner参数名称: [name, age]
    c.z.boot.launch.config.AppStartupRunner  : ApplicationRunner参数值: [18]
    c.z.boot.launch.config.AppStartupRunner  : ApplicationRunner参数: [--name=zimug, --age=18]

    BeanApplicationRunner run3()[--name=zimug, --age=18]

    c.z.b.l.config.CommandLineStartupRunner  : CommandLineRunner传入参数:[--name=zimug, --age=18]
    BeanCommandLineRunner run1()[--name=zimug, --age=18]
    e=18]
    BeanCommandLineRunner run2()[--name=zimug, --age=18]

    笔者经过多次测试发现,在测试结果中,这个优先级顺序一直如此,但目前无法确定这是否为常态

    • ApplicationRunner执行优先级高于CommandLineRunner

    • 以Bean的形式运行的Runner优先级要低于Component注解加implements Runner接口的方式

    • Order注解只能保证同类的CommandLineRunner或ApplicationRunner的执行顺序,不能跨类保证顺序

    四、总结

    CommandLineRunner、ApplicationRunner的核心用法是一致的,就是用于应用启动前的特殊代码执行。ApplicationRunner的执行顺序先于CommandLineRunner;ApplicationRunner将参数封装成了对象,提供了获取参数名、参数值等方法,操作上会方便一些。

    五、问题总结

    这是笔者在实践中真实遇到的问题,就是我定义了多个CommandLineRunner的实现。出现奇怪的问题是:当你定义多个CommandLineRunner的实现的时候,其中一个或者几个将不会执行。

    分析一下:下面的代码是SpringBootApplication启动项目之后会执行的代码,大家看代码中通过一个遍历来启动CommandLineRunner或者ApplicationRunner。也就是说,只有上一个CommandLineRunner执行完成之后,才会执行下一个CommandLineRunner,是同步执行的。

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
    		List<Object> runners = new ArrayList<>();
    		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    		AnnotationAwareOrderComparator.sort(runners);
    		for (Object runner : new LinkedHashSet<>(runners)) {
    			if (runner instanceof ApplicationRunner) {
    				callRunner((ApplicationRunner) runner, args);
    			}
    			if (runner instanceof CommandLineRunner) {
    				callRunner((CommandLineRunner) runner, args);
    			}
    		}
    	}

    所以,如果在CommandLineRunner某个实现run 方法体中调用了同步阻塞的API或者是一个 while(true) 循环,在遍历中处于该CommandLineRunner之后的其他实现将不会被执行。

    以上是springboot应用服务启动事件的监听怎么实现的详细内容。更多信息请关注PHP中文网其他相关文章!

    声明
    本文转载于:亿速云。如有侵权,请联系admin@php.cn删除
    JVM性能与其他语言JVM性能与其他语言May 14, 2025 am 12:16 AM

    JVM'SperformanceIsCompetitiveWithOtherRuntimes,operingabalanceOfspeed,安全性和生产性。1)JVMUSESJITCOMPILATIONFORDYNAMICOPTIMIZAIZATIONS.2)c提供NativePernativePerformanceButlanceButlactsjvm'ssafetyFeatures.3)

    Java平台独立性:使用示例Java平台独立性:使用示例May 14, 2025 am 12:14 AM

    JavaachievesPlatFormIndependencEthroughTheJavavIrtualMachine(JVM),允许CodeTorunonAnyPlatFormWithAjvm.1)codeisscompiledIntobytecode,notmachine-specificodificcode.2)bytecodeisisteredbytheybytheybytheybythejvm,enablingcross-platerssectectectectectross-eenablingcrossectectectectectection.2)

    JVM架构:深入研究Java虚拟机JVM架构:深入研究Java虚拟机May 14, 2025 am 12:12 AM

    TheJVMisanabstractcomputingmachinecrucialforrunningJavaprogramsduetoitsplatform-independentarchitecture.Itincludes:1)ClassLoaderforloadingclasses,2)RuntimeDataAreafordatastorage,3)ExecutionEnginewithInterpreter,JITCompiler,andGarbageCollectorforbytec

    JVM:JVM与操作系统有关吗?JVM:JVM与操作系统有关吗?May 14, 2025 am 12:11 AM

    JVMhasacloserelationshipwiththeOSasittranslatesJavabytecodeintomachine-specificinstructions,managesmemory,andhandlesgarbagecollection.ThisrelationshipallowsJavatorunonvariousOSenvironments,butitalsopresentschallengeslikedifferentJVMbehaviorsandOS-spe

    Java:写一次,在任何地方跑步(WORA) - 深入了解平台独立性Java:写一次,在任何地方跑步(WORA) - 深入了解平台独立性May 14, 2025 am 12:05 AM

    Java实现“一次编写,到处运行”通过编译成字节码并在Java虚拟机(JVM)上运行。1)编写Java代码并编译成字节码。2)字节码在任何安装了JVM的平台上运行。3)使用Java原生接口(JNI)处理平台特定功能。尽管存在挑战,如JVM一致性和平台特定库的使用,但WORA大大提高了开发效率和部署灵活性。

    Java平台独立性:与不同的操作系统的兼容性Java平台独立性:与不同的操作系统的兼容性May 13, 2025 am 12:11 AM

    JavaachievesPlatFormIndependencethroughTheJavavIrtualMachine(JVM),允许Codetorunondifferentoperatingsystemsswithoutmodification.thejvmcompilesjavacodeintoplatform-interploplatform-interpectentbybyteentbytybyteentbybytecode,whatittheninternterninterpretsandectectececutesoneonthepecificos,atrafficteyos,Afferctinginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginginging

    什么功能使Java仍然强大什么功能使Java仍然强大May 13, 2025 am 12:05 AM

    JavaispoperfulduetoitsplatFormitiondence,对象与偏见,RichstandardLibrary,PerformanceCapabilities和StrongsecurityFeatures.1)Platform-dimplighandependectionceallowsenceallowsenceallowsenceallowsencationSapplicationStornanyDevicesupportingJava.2)

    顶级Java功能:开发人员的综合指南顶级Java功能:开发人员的综合指南May 13, 2025 am 12:04 AM

    Java的顶级功能包括:1)面向对象编程,支持多态性,提升代码的灵活性和可维护性;2)异常处理机制,通过try-catch-finally块提高代码的鲁棒性;3)垃圾回收,简化内存管理;4)泛型,增强类型安全性;5)ambda表达式和函数式编程,使代码更简洁和表达性强;6)丰富的标准库,提供优化过的数据结构和算法。

    See all articles

    热AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智能驱动的应用程序,用于创建逼真的裸体照片

    AI Clothes Remover

    AI Clothes Remover

    用于从照片中去除衣服的在线人工智能工具。

    Undress AI Tool

    Undress AI Tool

    免费脱衣服图片

    Clothoff.io

    Clothoff.io

    AI脱衣机

    Video Face Swap

    Video Face Swap

    使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

    热门文章

    热工具

    Dreamweaver CS6

    Dreamweaver CS6

    视觉化网页开发工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神级代码编辑软件(SublimeText3)

    SublimeText3汉化版

    SublimeText3汉化版

    中文版,非常好用

    Dreamweaver Mac版

    Dreamweaver Mac版

    视觉化网页开发工具

    SublimeText3 英文版

    SublimeText3 英文版

    推荐:为Win版本,支持代码提示!