[英]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 從應用程序上下文運行所有CommandLineRunner
或ApplicationRunner
bean。 您不能通過任何參數選擇一個。
所以基本上你有兩種可能性:
CommandLineRunner
實現,並在每個實現中檢查參數以確定是否應該運行這個特殊的CommandLineRunner
。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.