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


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

    CommandLineRunner和ApplicationRunner的用法

    1. CommandLineRunner接口:
      • 方法签名: void run(String... args)
      • 参数类型: 字符串数组,表示应用程序启动时传递的命令行参数
      • 执行时机: 在Spring上下文准备好之后,但在调用ApplicationRunner之前执行。
    2. ApplicationRunner接口:
      • 方法签名: void run(ApplicationArguments args)
      • 参数类型: ApplicationArguments对象,提供对应用程序启动参数的更高级别访问
      • 执行时机: 在CommandLineRunner之后执行。

    这两个接口的目的是允许开发人员在应用程序启动完成后执行一些自定义的任务,例如加载初始化数据、执行数据迁移、启动后台任务等,它们都实现了org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean注解,这意味着只有在没有其他类型的Bean定义的情况下,才会自动配置它们。

    我们可以通过以下两种方式使用CommandLineRunnerApplicationRunner

    1. 通过实现接口并将其作为Spring Bean注册:

      • 创建一个类并实现CommandLineRunnerApplicationRunner接口
      • 实现接口的run方法,在该方法中编写您的自定义逻辑
      • 将实现类标记为@Component或使用其他适当的注解进行注解,以便使其成为Spring Bean
      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) throws Exception {
              // 在这里编写您的自定义逻辑
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
    2. 通过使用SpringApplicationrun方法参数进行注册:

      • SpringApplication.run方法中,将实现了CommandLineRunnerApplicationRunner接口的实例作为参数传递给run方法。
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.boot.CommandLineRunner;
      import org.springframework.boot.ApplicationRunner;
      
      @SpringBootApplication
      public class YourApplication implements CommandLineRunner, ApplicationRunner {
      
          public static void main(String[] args) {
              SpringApplication.run(YourApplication.class, args);
          }
      
          @Override
          public void run(String... args) throws Exception {
              // 在这里编写您的自定义逻辑
          }
      
          @Override
          public void run(ApplicationArguments args) throws Exception {
              // 在这里编写您的自定义逻辑
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22

    无论我们选择哪种方式,一旦应用程序启动完成,run方法将被调用,并且我们可以在其中编写我们的自定义逻辑。可以根据我们的需求选择使用CommandLineRunnerApplicationRunner接口。

    CommandLineRunner和ApplicationRunner的区别

    参数不同

    从上面的代码示例中,我们可以看到CommandLineRunner和ApplicationRunner的一个主要的不同就是它们的run方法的参数类型不同。CommandLineRunner的run方法接收一个String数组,它是直接从命令行传入的参数,比如java -jar myapp.jar arg1 arg2,那么arg1和arg2就会被传入到run方法中。而ApplicationRunner的run方法接收一个ApplicationArguments对象,它不仅包含了命令行传入的参数,还包含了其他的应用程序参数,比如--spring.profiles.active=dev,这些参数可以通过ApplicationArguments的方法来获取,比如args.getOptionNames()args.getNonOptionArgs()等。

    执行顺序不同

    另外一个不同就是CommandLineRunner和ApplicationRunner的执行顺序不同。如果我们在同一个应用程序中同时定义了多个CommandLineRunner和ApplicationRunner,那么它们的执行顺序是怎样的呢?答案是,首先执行所有的CommandLineRunner,然后执行所有的ApplicationRunner,而且它们都是按照优先级的顺序执行的,优先级越高,越先执行。我们可以通过@Order注解来指定它们的优先级,值越小,优先级越高,比如:

    // 优先级为1的CommandLineRunner
    @Component
    @Order(1)
    public class FirstCommandLineRunner implements CommandLineRunner {
        // 省略run方法
    }
    
    // 优先级为2的CommandLineRunner
    @Component
    @Order(2)
    public class SecondCommandLineRunner implements CommandLineRunner {
        // 省略run方法
    }
    
    // 优先级为1的ApplicationRunner
    @Component
    @Order(1)
    public class FirstApplicationRunner implements ApplicationRunner {
        // 省略run方法
    }
    
    // 优先级为2的ApplicationRunner
    @Component
    @Order(2)
    public class SecondApplicationRunner implements ApplicationRunner {
        // 省略run方法
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在上面的代码中,我们定义了两个CommandLineRunner和两个ApplicationRunner,并且分别指定了它们的优先级。那么它们的执行顺序是:

    • FirstCommandLineRunner
    • SecondCommandLineRunner
    • FirstApplicationRunner
    • SecondApplicationRunner

    CommandLineRunner和ApplicationRunner的使用场景

    那么,我们什么时候应该使用CommandLineRunner和ApplicationRunner呢?一般来说,它们都可以用来在Spring容器启动后执行一些初始化的任务,比如加载配置,初始化数据,运行测试等。但是,根据它们的不同,我们可以根据具体的需求来选择合适的接口。下面是一些可能的使用场景:

    • 如果我们需要在Spring容器启动后执行一些简单的任务,而且不需要获取任何的应用程序参数,那么我们可以使用CommandLineRunner,它的用法比较简单,只需要实现一个接口,然后写好run方法即可。
    • 如果我们需要在Spring容器启动后执行一些复杂的任务,而且需要获取一些应用程序参数,比如Spring的配置参数,那么我们可以使用ApplicationRunner,它的用法比较灵活,可以通过ApplicationArguments对象来获取各种参数,然后根据参数来执行不同的逻辑。
    • 如果我们需要在Spring容器启动后执行一些和命令行相关的任务,比如解析命令行参数,执行一些命令,那么我们可以使用CommandLineRunner,它可以直接获取命令行传入的参数,然后根据参数来执行不同的命令。
    • 如果我们需要在Spring容器启动后执行一些和应用程序相关的任务,比如启动其他的组件,调用其他的服务,那么我们可以使用ApplicationRunner,它可以获取应用程序的上下文,然后根据上下文来执行不同的任务。

    实操—获取SpringBoot启动后容器里面所有的Bean

    Spring Boot 在内部加载了大量的 bean,以最小的配置运行我们的应用程序。 我们想要找出所有这些 SpringBoot 加载的 Bean 及其类类型信息,就可以使用上面说的方法

    使用ApplicationContext获取所有已加载的 bean

    1)使用ApplicationContext.getBeanDefinitionNames()查找所有已加载 bean 的名称

    2)使用ApplicationContext.getBean(beanName)获取包含其运行时类型信息的 bean。

    @SpringBootApplication
    public class SpringBootWebApplication extends SpringBootServletInitializer implements CommandLineRunner {
    
    	@Override
    	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    		return application.sources(SpringBootWebApplication.class);
    	}
    
    	public static void main(String[] args) throws Exception {
    		SpringApplication.run(SpringBootWebApplication.class, args);
    	}
    
    	@Autowired
        private ApplicationContext appContext;
    
    	@Override
        public void run(String... args) throws Exception 
    	{
            String[] beans = appContext.getBeanDefinitionNames();
            Arrays.sort(beans);
            for (String bean : beans) 
            {
                System.out.println(bean + " of Type :: " + appContext.getBean(bean).getClass());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    输出信息如下:

    ....
    basicErrorController of Type :: class org.springframework.boot.autoconfigure.web.BasicErrorController
    beanNameHandlerMapping of Type :: class org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
    beanNameViewResolver of Type :: class org.springframework.web.servlet.view.BeanNameViewResolver
    characterEncodingFilter of Type :: class org.springframework.boot.web.filter.OrderedCharacterEncodingFilter
    conventionErrorViewResolver of Type :: class org.springframework.boot.autoconfigure.web.DefaultErrorViewResolver
    defaultServletHandlerMapping of Type :: class org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport$EmptyHandlerMapping
    defaultViewResolver of Type :: class org.springframework.web.servlet.view.InternalResourceViewResolver
    dispatcherServlet of Type :: class org.springframework.web.servlet.DispatcherServlet
    dispatcherServletRegistration of Type :: class org.springframework.boot.web.servlet.ServletRegistrationBean
    duplicateServerPropertiesDetector of Type :: class org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration$DuplicateServerPropertiesDetector
    embeddedServletContainerCustomizerBeanPostProcessor of Type :: class org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor
    error of Type :: class org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$SpelView
    errorAttributes of Type :: class org.springframework.boot.autoconfigure.web.DefaultErrorAttributes
    
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    Oracle故障案例 | 19C动态监听无法注册实例的处理
    Flash的学习
    爬虫-Day6-xpath解析
    测试时间不够,你会如何处理?
    Spring Cloud alibaba 集成 nacos 以及整合 Ribbon 与 Feign 实现负载调用(3)
    张量数据操作基础
    《持续交付:发布可靠软件的系统方法》- 读书笔记(八)
    从vue的角度看android Fragment
    微服务实战|集中配置中心Config对称加密实战
    【刷题笔记8】LeetCode 48. 旋转图像(数组模拟)
  • 原文地址:https://blog.csdn.net/belongtocode/article/details/134489842