簡體   English   中英

多個 Spring 基於命令行參數啟動 CommandLineRunner

[英]Multiple Spring boot CommandLineRunner based on command line argument

我已經使用 spring 雲任務創建了 spring 啟動應用程序,該任務應該執行一些命令(任務)。 每個任務/命令都是短期任務,所有任務都是從命令行開始,做一些簡短的 ETL 工作並完成執行。

有一個 spring 引導 jar 包含所有命令/任務。 每個任務都是 CommandLineRunner,我喜歡根據命令行的參數來決定將執行哪些任務(一個或多個)。 這樣做的最佳做法是什么? 我不喜歡有臟代碼問“if else”或類似的東西。

你也可以讓你的 CommandLineRunner 實現 @Component 和 @ConditionalOnExpression("${someproperty:false}")

然后有多個配置文件,將 someproperty 設置為 true 以將那些 CommandLineRunners 包含在上下文中。

@Component
@Slf4j
@ConditionalOnExpression("${myRunnerEnabled:false}")
public class MyRunner implements CommandLineRunner {
    @Override
    public void run(String ... args) throws Exception {
        log.info("this ran");
    }
}

並在 yml application-myrunner.yml

myRunnerEnabled: true
@SpringBootApplication
public class SpringMain {
    public static void main(String ... args) {
        SpringApplication.run(SpringMain.class, args);
    }
}

Spring Boot 從應用程序上下文運行所有CommandLineRunnerApplicationRunner bean。 您不能通過任何參數選擇一個。

所以基本上你有兩種可能性:

  1. 您有不同的CommandLineRunner實現,並在每個實現中檢查參數以確定是否應該運行這個特殊的CommandLineRunner
  2. 您只實現了一個充當調度程序的CommandLineRunner 代碼可能如下所示:

這是您的跑步者將實現的新接口:

public interface MyCommandLineRunner {
    void run(String... strings) throws Exception;
}

然后定義實現並用名稱標識它們:

@Component("one")
public class MyCommandLineRunnerOne implements MyCommandLineRunner {
    private static final Logger log = LoggerFactory.getLogger(MyCommandLineRunnerOne.class);

    @Override
    public void run(String... strings) throws Exception {
        log.info("running");
    }
}

@Component("two")
public class MyCommandLineRunnerTwo implements MyCommandLineRunner {
    private static final Logger log = LoggerFactory.getLogger(MyCommandLineRunnerTwo.class);
    @Override
    public void run(String... strings) throws Exception {
        log.info("running");
    }
}

然后在您的單個CommandLineRunner實現中,您獲取應用程序上下文並按名稱解析所需的 bean,我的示例僅使用第一個參數,並調用它的MyCommandLineRunner.run()方法:

@Component
public class CommandLineRunnerImpl implements CommandLineRunner, ApplicationContextAware {
    private ApplicationContext applicationContext;


    @Override
    public void run(String... strings) throws Exception {
        if (strings.length < 1) {
            throw new IllegalArgumentException("no args given");
        }

        String name = strings[0];
        final MyCommandLineRunner myCommandLineRunner = applicationContext.getBean(name, MyCommandLineRunner.class);
        myCommandLineRunner.run(strings);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

奇怪的是沒有內置的機制來選擇一組 CommandLineRunner。 默認情況下,所有這些都被執行。

我重用了 - 也許不正確 - Profile 機制,即我用 @org.springframework.context.annotation.Profile("mycommand") 注釋了每個 CommandLineRunner,並且我選擇了我想用 System 屬性執行的一個 -Dspring .profiles.active=我的命令

更多關於 Profile 機制的信息,請參考https://www.baeldung.com/spring-profiles

類似於這個答案https://stackoverflow.com/a/44482525/986160但使用注入和較少的配置。

有一個類似的要求,對我有用的是讓一個CommandLineApps類實現CommandLineRunner ,然后將所有其他命令行運行程序作為@Component注入,並使用第一個參數委托給注入的運行程序之一。 請注意,注入的那些不應擴展CommandLineRunner並且不應被注釋為@SpringBootAppplication

重要提示:請注意,如果您將調用放入 crontab 中,則如果未完成,則調用將破壞前一個調用。

下面是一個例子:

@SpringBootApplication
public class CommandLineApps implements CommandLineRunner {

    @Autowired
    private FetchSmsStatusCmd fetchSmsStatusCmd;

    @Autowired
    private OffersFolderSyncCmd offersFolderSyncCmd;

    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(CommandLineApps.class,  args);
        ctx.close();
    }

    @Override
    public void run(String... args) {

        if (args.length == 0) {
            return;
        }

        List<String> restOfArgs = Arrays.asList(args).subList(1, args.length);

        switch (args[0]) {
            case "fetch-sms-status":
                fetchSmsStatusCmd.run(restOfArgs.toArray(new String[restOfArgs.size()]));
                break;
            case "offers-folder-sync":
                offersFolderSyncCmd.run(restOfArgs.toArray(new String[restOfArgs.size()]));
                break;
        }
    }
}
@Component
public class FetchSmsStatusCmd {

    [...] @Autowired dependencies    

    public void run(String[] args) {

        if (args.length != 1) {
            logger.error("Wrong number of arguments");
            return;
        }
        [...]
    }
 }

您可以在單個文件或應用程序中擁有多個 CommandLineRunner。 需要執行哪一個(調用“運行”方法)由唯一的 - 訂單(@Order 注釋)決定。 如果您需要執行多個 CommandLineRunner,請編寫它們,將值傳遞給 Order 注解。

@Bean
    @Order(value = 1)
    public CommandLineRunner demo1(CustomerRepository customerRepository){
        return (args) ->{
            customerRepository.save(new Customer("Viji", "Veerappan"));
            customerRepository.save(new Customer("Dhinesh", "Veerappan"));
            customerRepository.save(new Customer("Senbagavalli", "Veerappan"));
        };
    }



@Order(value = 2)
    public CommandLineRunner demo(CustomerRepository customerRepository){
        return (args) ->{

            // Save all the customers
            customerRepository.save(new Customer("Mahith", "Saravanan"));
            customerRepository.save(new Customer("Pooshi", "Saravanan"));
            customerRepository.save(new Customer("Dharma", "Saravanan"));
            customerRepository.save(new Customer("Mookayee", "Veerayandi"));
            customerRepository.save(new Customer("Chellammal", "Kandasamy"));

            //fetch all customer
            log.info("Fetching all the customers by findAll()");
            log.info("----------------------------------------");
            for(Customer customer : customerRepository.findAll()){
                log.info(customer.toString());
            }
            log.info("");

            //fetch one customer by Id
            log.info("Fetch one customer Id by findById(1L)");
            log.info("----------------------------------------");
            log.info(customerRepository.findById(1L).toString());
            log.info("");

            //fetch by last name
            log.info("Fetch all customers that have lastname = Saravanan");
            log.info("---------------------------------------------------");
            for(Customer customer: customerRepository.findByLastName("Saravanan")){
                log.info(customer.toString());
            }
            /*customerRepository.findByLastName("Saravanan").forEach( saravanan ->{
                saravanan.toString();
            });*/
        };
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM