编辑此页面

使用 Picocli 的命令行模式

Picocli 是一个用于创建富命令列应用程序的开源工具。

Quarkus 支持使用 Picocli。本指南包含 picocli 扩展用法的示例。

如果您不熟悉 Quarkus 命令模式,请先阅读 命令模式参考指南

扩展

在配置好 Quarkus 项目后,您可以在项目根目录下运行以下命令,将 picocli 扩展添加到项目中。

CLI
quarkus extension add picocli
Maven
./mvnw quarkus:add-extension -Dextensions='picocli'
Gradle
./gradlew addExtension --extensions='picocli'

这会将以下内容添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-picocli</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-picocli")

构建命令行应用程序

简单应用程序

可以用如下方式创建一个只有单个 Command 的简单 Picocli 应用程序:

package com.acme.picocli;

import picocli.CommandLine;

import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;

@CommandLine.Command (1)
public class HelloCommand implements Runnable {

    @CommandLine.Option(names = {"-n", "--name"}, description = "Who will we greet?", defaultValue = "World")
    String name;

    private final GreetingService greetingService;

    public HelloCommand(GreetingService greetingService) { (2)
        this.greetingService = greetingService;
    }

    @Override
    public void run() {
        greetingService.sayHello(name);
    }
}

@Dependent
class GreetingService {
    void sayHello(String name) {
        System.out.println("Hello " + name + "!");
    }
}
1 如果只有一个类用 picocli.CommandLine.Command 标注,它将自动用作命令行应用程序的入口点。
2 所有用 picocli.CommandLine.Command 标注的类都将注册为 CDI bean。
@CommandLine.Command 标注的 Bean 不应使用代理作用域(例如,不要使用 @ApplicationScoped),因为 Picocli 将无法在这些 Bean 中设置字段值。默认情况下,此 Picocli 扩展将用 @Dependent 作用域注册用 @CommandLine.Command 标注的类。如果您需要使用代理作用域,请标注 setter 而不是字段,例如:
@CommandLine.Command
@ApplicationScoped
public class EntryCommand {
    private String name;

    @CommandLine.Option(names = "-n")
    public void setName(String name) {
        this.name = name;
    }
}

具有多个 Command 的命令行应用程序

当有多个类具有 picocli.CommandLine.Command 注解时,其中一个需要同时用 io.quarkus.picocli.runtime.annotations.TopCommand 标注。这可以通过 quarkus.picocli.top-command 属性覆盖。

package com.acme.picocli;

import io.quarkus.picocli.runtime.annotations.TopCommand;
import picocli.CommandLine;

@TopCommand
@CommandLine.Command(mixinStandardHelpOptions = true, subcommands = {HelloCommand.class, GoodByeCommand.class})
public class EntryCommand {
}

@CommandLine.Command(name = "hello", description = "Greet World!")
class HelloCommand implements Runnable {

    @Override
    public void run() {
        System.out.println("Hello World!");
    }
}

@CommandLine.Command(name = "goodbye", description = "Say goodbye to World!")
class GoodByeCommand implements Runnable {

    @Override
    public void run() {
        System.out.println("Goodbye World!");
    }
}

自定义 Picocli CommandLine 实例

您可以通过创建自己的 Bean 实例来定制 picocli 扩展使用的 CommandLine 类。

package com.acme.picocli;

import io.quarkus.picocli.runtime.PicocliCommandLineFactory;
import io.quarkus.picocli.runtime.annotations.TopCommand;
import picocli.CommandLine;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;

@TopCommand
@CommandLine.Command
public class EntryCommand implements Runnable {
    @CommandLine.Spec
    CommandLine.Model.CommandSpec spec;

    @Override
    public void run() {
        System.out.println("My name is: " + spec.name());
    }
}

@ApplicationScoped
class CustomConfiguration {

    @Produces
    CommandLine customCommandLine(PicocliCommandLineFactory factory) { (1)
        return factory.create().setCommandName("CustomizedName");
    }
}
1 PicocliCommandLineFactory 将创建一个 CommandLine 实例,并注入 TopCommandCommandLine.IFactory

为每个 Profile 设置不同的入口命令

可以使用 @IfBuildProfile 为每个 Profile 设置不同的入口命令。

@ApplicationScoped
public class Config {

    @Produces
    @TopCommand
    @IfBuildProfile("dev")
    public Object devCommand() {
        return DevCommand.class; (1)
    }

    @Produces
    @TopCommand
    @IfBuildProfile("prod")
    public Object prodCommand() {
        return new ProdCommand("Configured by me!");
    }

}
1 在这里您可以返回 java.lang.Class 的实例。在这种情况下,CommandLine 将尝试使用 CommandLine.IFactory 来实例化该类。

使用解析的参数配置 CDI Bean

您可以使用 Event<CommandLine.ParseResult> 或直接使用 CommandLine.ParseResult 来根据 Picocli 解析的参数配置 CDI Bean。此事件将在扩展创建的 QuarkusApplication 类中生成。如果您提供自己的 @QuarkusMain,则不会触发此事件。CommandLine.ParseResult 是从默认的 CommandLine Bean 创建的。

@CommandLine.Command
public class EntryCommand implements Runnable {

    @CommandLine.Option(names = "-c", description = "JDBC connection string")
    String connectionString;

    @Inject
    DataSource dataSource;

    @Override
    public void run() {
        try (Connection c = dataSource.getConnection()) {
            // Do something
        } catch (SQLException throwables) {
            // Handle error
        }
    }
}

@ApplicationScoped
class DatasourceConfiguration {

    @Produces
    @ApplicationScoped (1)
    DataSource dataSource(CommandLine.ParseResult parseResult) {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        ds.setURL(parseResult.matchedOption("c").getValue().toString());
        return ds;
    }
}
1 @ApplicationScoped 用于延迟初始化

提供您自己的 QuarkusMain

您还可以提供自己的、用 QuarkusMain 标注的应用程序入口点(如 命令模式参考指南中所述)。

package com.acme.picocli;

import io.quarkus.runtime.QuarkusApplication;
import io.quarkus.runtime.annotations.QuarkusMain;
import picocli.CommandLine;

import jakarta.inject.Inject;

@QuarkusMain
@CommandLine.Command(name = "demo", mixinStandardHelpOptions = true)
public class ExampleApp implements Runnable, QuarkusApplication {
    @Inject
    CommandLine.IFactory factory; (1)

    @Override
    public void run() {
        // business logic
    }

    @Override
    public int run(String... args) throws Exception {
        return new CommandLine(this, factory).execute(args);
    }
}
1 picocli 扩展创建的 Quarkus 兼容 CommandLine.IFactory Bean。

开发模式

在开发模式下,即运行 mvn quarkus:dev 时,应用程序将在每次按下 空格键 时执行并重新启动。您还可以通过 quarkus.args 系统属性为您的命令行应用程序传递参数,例如 mvn quarkus:dev -Dquarkus.args='--help'mvn quarkus:dev -Dquarkus.args='-c -w --val 1'。对于 Gradle 项目,可以使用 --quarkus-args 传递参数。

如果您正在创建一个典型的 Quarkus 应用程序(例如,基于 HTTP 的服务)并且包含命令行功能,您需要以不同的方式处理应用程序的生命周期。在命令的 Runnable.run() 方法中,请确保使用 Quarkus.waitForExit()Quarkus.asyncExit()。这将防止应用程序过早关闭,并确保正确的关闭过程。

打包您的应用程序

Picocli 命令行应用程序可以打包成多种格式(例如,JAR、原生可执行文件),并可以发布到各种存储库(例如,Homebrew、Chocolatey、SDKMAN!)。

作为 JAR

Picocli 命令行应用程序是一个标准的 Quarkus 应用程序,因此可以以各种打包格式(例如,fast-jar、uber-jar)发布为 JAR。

在命令行应用程序的上下文中,如果您计划将 JAR 原样发布,构建 uber-jar 会更实用。

有关如何构建 uber-jar 的更多信息,请参阅我们的文档。

然后您可以使用标准的 java -jar your-application.jar 命令执行应用程序。

使用诸如 really-executable-jar-maven-plugin 等插件可以方便地简化命令行应用程序的执行。

作为原生可执行文件

您还可以构建 原生可执行文件,但请记住,原生可执行文件不是可移植的,并且您需要每个支持的平台一个二进制文件。

发布应用程序

将您的命令行应用程序发布到存储库可以大大简化其使用。根据您的需求,有各种应用程序存储库可用,例如适用于 macOS 的 SDKMAN!Homebrew,或者适用于 Windows 的 Chocolatey

为了发布到这些存储库,我们推荐使用 JReleaser

JReleaser 会在您的 JAR 周围添加可执行包装器,以便轻松执行您的应用程序。

更多信息

您还可以查阅 Picocli 官方文档,以获取有关如何打包 Picocli 应用程序的一般信息。

Kubernetes 支持

一旦有了命令行应用程序,您还可以通过添加 kubernetes 扩展来生成在 Kubernetes 中安装和使用此应用程序所需的资源。要安装 kubernetes 扩展,请在项目根目录下运行以下命令。

CLI
quarkus extension add kubernetes
Maven
./mvnw quarkus:add-extension -Dextensions='kubernetes'
Gradle
./gradlew addExtension --extensions='kubernetes'

这会将以下内容添加到您的 pom.xml

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-kubernetes</artifactId>
</dependency>

然后,使用以下命令构建应用程序:

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

Kubernetes 扩展将检测到 Picocli 扩展的存在,因此将在 target/kubernetes/ 目录中生成一个 Job 资源,而不是一个 Deployment 资源。

如果您不想生成 Job 资源,可以使用 quarkus.kubernetes.deployment-kind 属性指定要生成的资源。例如,如果您想生成 Deployment 资源,请使用 quarkus.kubernetes.deployment-kind=Deployment

此外,您可以通过 quarkus.kubernetes.arguments 属性提供 Kubernetes Job 将使用的参数。例如,在添加属性 quarkus.kubernetes.arguments=A,B 并构建项目后,将生成以下 Job 资源:

apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app.kubernetes.io/name: app
    app.kubernetes.io/version: 0.1-SNAPSHOT
  name: app
spec:
  completionMode: NonIndexed
  suspend: false
  template:
    metadata:
      labels:
        app.kubernetes.io/name: app
        app.kubernetes.io/version: 0.1-SNAPSHOT
    spec:
      containers:
        - args:
            - A
            - B
          env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: docker.io/user/app:0.1-SNAPSHOT
          imagePullPolicy: Always
          name: app
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
      restartPolicy: OnFailure
      terminationGracePeriodSeconds: 10

最后,每次在 Kubernetes 中安装时,Kubernetes Job 都将启动。您可以在此 文档中了解有关如何运行 Kubernetes Job 的更多信息。

配置参考

构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖

配置属性

类型

默认

io.quarkus.picocli.runtime.annotations.TopCommand 标注的 Bean 的名称,或者将用作 Picocli CommandLine 实例入口点的类的 FQCN。此类需要用 picocli.CommandLine.Command 标注。

环境变量:QUARKUS_PICOCLI_TOP_COMMAND

显示更多

字符串

相关内容