执行单个命令并退出Spring Shell 2

woe*_*ler 6 java spring-boot spring-shell

我偶然发现了这个问题,解释了如何在使用单个命令从命令行调用Spring Shell应用程序后退出.但是,使用Spring Boot在2.0.0中测试它,似乎不再是用命令参数调用JAR将执行该命令然后退出的情况.shell只是正常启动而不执行提供的命令.是否仍然可以这样做?如果没有,是否可以将参数从JAR执行传递给Spring Shell,然后在执行后触发退出?

例如,假设我有一个命令,import它有几个选项.它可以在shell中运行,如下所示:

$ java -jar my-app.jar

> import -f /path/to/file.txt --overwrite
Successfully imported 'file.txt'

> exit
Run Code Online (Sandbox Code Playgroud)

但是为了构建一个可以利用这个功能的脚本,能够简单地执行和退出会很好:

$ java -jar my-app.jar import -f /path/to/file.txt --overwrite
Successfully imported 'file.txt'
Run Code Online (Sandbox Code Playgroud)

woe*_*ler 1

我找到了一个不错的小解决方法。我没有创建一个ApplicationRunner模仿 v1 行为的类(这很棘手,因为它JLineInputProvider是一个私有类),而是创建了一个基于活动 Spring 配置文件的可选加载类。我使用 JCommander 定义 CLI 参数,使我能够为交互式 shell 和一次性执行使用相同的命令。运行不带参数的 Spring Boot JAR 会触发交互式 shell。使用参数运行它会触发一劳永逸的执行。

@Parameters
public class ImportParameters {

  @Parameter(names = { "-f", "--file" }, required = true, description = "Data file")
  private File file;

  @Parameter(names = { "-t", "--type" }, required = true, description = "Data type")
  private DataType dataType;

  @Parameter(names = { "-o", "--overwrite" }, description = "Flag to overwrite file if it exists")
  private Boolean overwrite = false;

  /* getters and setters */
}

public class ImportCommandExecutor {

  public void run(ImportParameters params) throws Exception {
    // import logic goes here
  }

}

/* Handles interactive shell command execution */
@ShellComponent
public class JLineInputExecutor {

  // All command executors are injected here
  @Autowired private ImportCommandExecutor importExecutor;
  ...

  @ShellMethod(key = "import", value = "Imports the a file of a specified type.")
  public String importCommand(@ShellOption(optOut = true) ImportParameters params) throws Exception {
    importCommandExecutor.run(params);
  }

  ...

}

/* Handles one-off command execution */
public class JCommanderInputExecutor implements ApplicationRunner {

  // All command executors are injected here
  @Autowired private ImportCommandExecutor importExecutor;
  ...

  @Override
  public void run(ApplicationArguments args) throws Exception {

    // Create all of the JCommander argument handler objects
    BaseParameters baseParameters = new BaseParameters();
    ImportParameters importParameters = new ImportParameters();
    ...

    JCommander jc = newBuilder().
      .acceptUnknownOptions(true)
      .addObject(baseParameters)
      .addCommand("import", importParameters)
      ...
      .build();

    jc.parse(args);
    String mainCommand = jc.getParsedCommand();

    if ("import".equals(mainCommand)){
      importExecutor.run(importParameters);
    } else if (...) {
      ...
    }  

  }
}

@Configuration
@Profile({"CLI"})
public class CommandLineInterfaceConfiguration {

  // All of my command executors are defined as beans here, as well as other required configurations for both modes of execution 
  @Bean
  public ImportCommandExecutor importExecutor (){
    return new ImportCommandExecutor();
  }
  ...

}

@Configuration
@Profile({"SINGLE_COMMAND"})
public class SingleCommandConfiguration {

  @Bean
  public JCommanderInputExecutor commandLineInputExecutor(){
    return new JCommanderInputExecutor();
  }

}

@SpringBootApplication
public class Application {

  public static void main(String[] args) throws IOException {
    String[] profiles = getActiveProfiles(args);
    SpringApplicationBuilder builder = new SpringApplicationBuilder(Application.class);
    builder.bannerMode((Mode.LOG));
    builder.web(false);
    builder.profiles(profiles);
    System.out.println(String.format("Command line arguments: %s  Profiles: %s",
        Arrays.asList(args), Arrays.asList(profiles)));
    builder.run(args);
  }

  private static String[] getActiveProfiles(String[] args){
    return Arrays.asList(args).contains("-X") ? new String[]{"CLI", "SINGLE_COMMAND"} : new String[]{"CLI"};
  }

}
Run Code Online (Sandbox Code Playgroud)

现在我只需运行可执行 JAR 即可触发交互式客户端:

java -jar app.jar
> import -f /path/to/file.txt -t GENE -o
> quit()
Run Code Online (Sandbox Code Playgroud)

或者,如果我在命令行上传递“-X”参数,应用程序将执行然后退出:

java -jar app.jar -X import -f /path/to/file.txt -t GENE -o
Run Code Online (Sandbox Code Playgroud)