Spring Boot 2 Combat: кастомный запуск и логика работы

Spring Boot Java задняя часть

1. Введение

不知道你有没有接到这种需求,项目启动后立马执行一些逻辑。比如缓存预热,或者上线后的广播之类等等。可能现在没有但是将来会有的。想想你可能的操作, 写个接口上线我调一次行吗? НЕТ! НЕТ! НЕТ!这种初级菜鸟才干的事。今天告诉你个骚操作使得你的代码更加优雅,逼格更高。

2. Интерфейс Commandlinerunner

 package org.springframework.boot;
 
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
 
 /**
  * Interface used to indicate that a bean should <em>run</em> when it is contained within
  * a {@link SpringApplication}. Multiple {@link CommandLineRunner} beans can be defined
  * within the same application context and can be ordered using the {@link Ordered}
  * interface or {@link Order @Order} annotation.
  * <p>
  * If you need access to {@link ApplicationArguments} instead of the raw String array
  * consider using {@link ApplicationRunner}.
  *
  * @author Dave Syer
  * @see ApplicationRunner
  */
 @FunctionalInterface
 public interface CommandLineRunner {
 
     /**
      * Callback used to run the bean.
      * @param args incoming main method arguments
      * @throws Exception on error
      */
     void run(String... args) throws Exception;
 
 }

CommandLineRunnerРоль заключается в том, что при запуске springApplication несколько определенных в одном и том же контексте приложенияCommandLineRunnerТипSpring BeanВыполнить в отмеченном порядке. Если вы хотите вместо этого получить массивargsПараметры можно заменить другим интерфейсомorg.springframework.boot.ApplicationRunner.

talk is cheap show your codeДалее я проведу демонстрацию.

2.1 Более высокий приоритетCommandLineRunnerвыполнить

 package cn.felord.begin;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.core.Ordered;
 import org.springframework.stereotype.Component;
 
 /**
  * 优先级比较高 通过实现接口{@link Ordered}的方式 来指定优先级
  *  命令行测试参数     --foo=bar --dev.name=码农小胖哥  java,springboot
  * @author Felordcn
  * @since 2019/6/17 23:06
  */
 @Slf4j
 @Component
 public class HighOrderCommandLineRunner implements CommandLineRunner , Ordered {
     @Override
     public void run(String... args) throws Exception {

       log.info("i am  highOrderRunner");
     }
 
     @Override
     public int getOrder() {
         return Ordered.HIGHEST_PRECEDENCE;
     }
 } 

2.2 Более низкий приоритетCommandLineRunnerвыполнить:

 package cn.felord.begin;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.core.Ordered;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Component;
 
 /**
  * 优先级比较低 通过注解{@link Order}方式来指定优先级
  * 比最优大64 说明会在 {@link HighOrderCommandLineRunner} 之后执行
  *
  * @author Felord
  * @since 2019/6/17 23:07
  */
 @Slf4j
 @Order(Ordered.HIGHEST_PRECEDENCE + 64)
 @Component
 public class LowOrderCommandLineRunner implements CommandLineRunner {
     @Override
     public void run(String... args) throws Exception {
         log.info("i am  lowOrderRunner");
     }
 }

2.3 ИспользованиеApplicationRunnerРеализовать самый низкий приоритет:

 package cn.felord.begin;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
 import org.springframework.core.Ordered;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import java.util.List;
 
 /**
  * 优先级最低的实现
  * @author Felordcn
  * @since 2019/6/18 22:13
  */
 @Slf4j
 @Component
 public class DefaultApplicationRunner implements ApplicationRunner, Ordered {
     @Override
     public void run(ApplicationArguments args) throws Exception {
 
         log.info("i am applicationRunner");
         
     }
 
     @Override
     public int getOrder() {
         return Ordered.HIGHEST_PRECEDENCE+65;
     }
 }

После запуска springboot консоль выводит результат выполнения:

 2019-11-02 21:18:14.603  INFO 10244 --- [           main] c.f.begin.HighOrderCommandLineRunner   : i am  highOrderRunner
 2019-11-02 21:18:14.604  INFO 10244 --- [           main] c.f.begin.LowOrderCommandLineRunner    : i am  lowOrderRunner
 2019-11-02 21:18:14.604  INFO 10244 --- [           main] c.f.begin.DefaultApplicationRunner     : i am applicationRunner

3. Расширенная операция - весенние загрузки, прочитанные по параметрам командной строки Начало впрыска

Для достижения желаемых результатов мы начали с. Так в чем же разница между этими двумя интерфейсами?SpringЧиновник не наестся и не имеет отношения к двум подбрасывателям, должна быть разница, по методу интерфейсаrunИз метода видно, что параметры разные, дополнительные научно-популярныеSpring BootКак передать дополнительные аргументы для выполнения через командную строкуjava -jarПерейти кmainметод, правила следующие

  • Ключевое значение отформатировано--K=VРазделяйте несколько пробелами
  • Значение, разделенное несколькими пробелами
    Откройте элемент конфигурации основного метода в инструменте разработки идей и выполните следующую настройку.То же самое верно и для других инструментов IDE. Содержимое параметра:

    --foo=bar --dev.name=код фермер маленький толстый брат java springboot

HighOrderCommandLineRunnerраспечатать этоargsпараметр:

 package cn.felord.begin;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.core.Ordered;
 import org.springframework.stereotype.Component;
 
 /**
  * 优先级比较高 通过实现接口{@link Ordered}的方式 来指定优先级
  *  命令行测试参数     --foo=bar --dev.name=码农小胖哥  java,springboot
  * @author dax
  * @since 2019/6/17 23:06
  */
 @Slf4j
 @Component
 public class HighOrderCommandLineRunner implements CommandLineRunner , Ordered {
     @Override
     public void run(String... args) throws Exception {
 
         for (String arg : args) {
             System.out.println("arg = " + arg);
         }
 
       log.info("i am  highOrderRunner");
     }
 
     @Override
     public int getOrder() {
         return Ordered.HIGHEST_PRECEDENCE;
     }
 }

потомDefaultApplicationRunnerизApplicationArgumentsТакже смотрим:

 package cn.felord.begin;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.ApplicationArguments;
 import org.springframework.boot.ApplicationRunner;
 import org.springframework.core.Ordered;
 import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 
 import java.util.List;
 
 /**
  * @author Felord
  * @since 2019/6/18 22:13
  */
 @Slf4j
 @Component
 public class DefaultApplicationRunner implements ApplicationRunner, Ordered {
     @Override
     public void run(ApplicationArguments args) throws Exception {
 
         log.info("i am applicationRunner");
 
         args.getOptionNames().forEach(System.out::println);
         System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>");
         String[] sourceArgs = args.getSourceArgs();
 
         if (sourceArgs!=null){
             for (String sourceArg : sourceArgs) {
                 System.out.println("sourceArg = " + sourceArg);
             }
         }
 
 
         System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
         List<String> foo = args.getOptionValues("foo");
         if (!CollectionUtils.isEmpty(foo)){
             foo.forEach(System.out::println);
         }
 
         System.out.println("++++++++++++");
         List<String> nonOptionArgs = args.getNonOptionArgs();
         System.out.println("nonOptionArgs.size() = " + nonOptionArgs.size());
         nonOptionArgs.forEach(System.out::println);
     }
 
     @Override
     public int getOrder() {
         return Ordered.HIGHEST_PRECEDENCE+65;
     }
 }

Начать сначалаSpring BootКонсоль выводит результат:

 
 arg = --foo=bar
 arg = --dev.name=码农小胖哥
 arg = java
 arg = springboot
 2019-11-02 21:18:14.603  INFO 10244 --- [           main] c.f.begin.HighOrderCommandLineRunner   : i am  highOrderRunner
 2019-11-02 21:18:14.604  INFO 10244 --- [           main] c.f.begin.LowOrderCommandLineRunner    : i am  lowOrderRunner
 2019-11-02 21:18:14.604  INFO 10244 --- [           main] c.f.begin.DefaultApplicationRunner     : i am applicationRunner
 dev.name
 foo
 >>>>>>>>>>>>>>>>>>>>>>>>>>
 sourceArg = --foo=bar
 sourceArg = --dev.name=码农小胖哥
 sourceArg = java
 sourceArg = springboot
 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 bar
 ++++++++++++
 nonOptionArgs.size() = 2
 java
 springboot

Мы обнаружили, что можем использовать эти два интерфейса для чтенияSpring Bootаргументы командной строки. На самом деле, мы также можем использовать@ValueАннотацию читать, здесь не поясняется, если интересно, можете попробовать сами. сюдаApplicationRunnerиCommandLineRunnerРазница очевидна из консоли.

4. ApplicationRunnerиCommandLineRunnerразница

сверхуlogмы знаемarg=заCommandLineRunnerизargs数组打印,仅仅单纯把上面的参数以空格为规则解析成了原汁原味的数组。 иApplicationRunnerявляется более изысканным. Узнай, распечатавApplicationArgumentsПредоставляет несколько полезных методов разбора параметров:

  • args.getOptionNames()это получить пару ключ-значение--K=VсерединаK
  • args.getOptionValues("foo")раньше проходилKчтобы получить значение пары ключ-значениеV
  • args.getSourceArgs()ЭквивалентноCommandLineRunnerизargsмножество
  • args.getNonOptionArgs()Худшее использовалось, чтобы получить одну собаку

Предостережение заключается в том, чтобы иметь дело с нулевыми указателями при разборе ApplicationArguments.

5. Резюме

Сегодня мы проходимCommandLineRunnerиApplicationRunnerобъяснять. Как решитьSpring BootПроблема выполнения некоторой логики при запуске и расстановка приоритетов логики множественного запуска. В то же время мы делаем шаг вперед и читаем эти два метода.Spring BootПараметр запуска. А затем также выяснил тонкие различия между двумя интерфейсами. Надеюсь, это поможет вам.

关注公众号:Felordcn获取更多资讯

Личный блог: https://felord.cn