Creating Your First Application

学习如何创建 Hello World Quarkus 应用程序。本指南介绍:

  • Bootstrapping an application

  • 创建 Jakarta REST 端口

  • Injecting beans

  • Functional tests

  • Packaging of the application

Prerequisites

如要完成本指南,您需要:

  • Roughly 15 minutes

  • An IDE

  • 安装了 JDK 17+,已正确配置 JAVA_HOME

  • Apache Maven ${proposed-maven-version}

  • 如果你想使用 Quarkus CLI, 则可以选择使用

  • 如果你想构建一个本机可执行文件(或如果你使用本机容器构建,则使用 Docker),则可以选择安装 Mandrel 或 GraalVM 以及 configured appropriately

Verify Maven is using the Java you expect

如果你安装了多个 JDK,则不确定 Maven 是否会选择预期的 Java,你可能会得到意外的结果。你可以通过运行 `mvn --version`验证 Maven 使用哪个 JDK。

Architecture

在本指南中,我们将创建一个直接服务的应用程序 `hello`端口。为了演示依赖注入,此端口使用了一个 `greeting`bean。

getting started architecture

本指南还介绍了端口测试。

Solution

我们建议你按照 Bootstrapping the project以下的说明逐步创建该应用程序。

但是,你可以直接转到已完成的示例。

下载 $${quickstarts-base-url}/archive/main.zip[归档] 或克隆 git 存储库:

git clone {quickstarts-clone-url}

解决方案位于 getting-started directory

Bootstrapping the project

创建新 Quarkus 项目的最简单方法是打开一个终端并运行以下命令:

CLI
quarkus create app {create-app-group-id}:{create-app-artifact-id} \
    --no-code
cd {create-app-artifact-id}

要创建一个 Gradle 项目,添加 --gradle--gradle-kotlin-dsl 选项。 有关如何安装和使用 Quarkus CLI 的详细信息,请参见 Quarkus CLI 指南。

Maven
mvn {quarkus-platform-groupid}:quarkus-maven-plugin:{quarkus-version}:create \
    -DprojectGroupId={create-app-group-id} \
    -DprojectArtifactId={create-app-artifact-id} \
    -DnoCode
cd {create-app-artifact-id}

要创建一个 Gradle 项目,添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

适用于 Windows 用户:

  • 如果使用 cmd,(不要使用反斜杠 \ ,并将所有内容放在同一行上)

  • 如果使用 Powershell,将 -D 参数用双引号引起来,例如 "-DprojectArtifactId={create-app-artifact-id}"

它在 `./getting-started`中生成以下内容:

  • the Maven structure

  • 公开于 `/hello`上的 `org.acme.GreetingResource`资源

  • an associated unit test

  • 启动应用程序后可以在 `http://localhost:8080`访问的登录页面

  • 在 `src/main/docker`中针对 `native`和 `jvm`模式的 `Dockerfile`文件示例

  • the application configuration file

一旦生成,查看 pom.xml。你会发现 Quarkus BOM 的导入,允许你省略 Quarkus 不同依赖的版本。此外,你可以看到 quarkus-maven-plugin,它负责应用程序的封装,并且也会提供开发模式。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>${quarkus.platform.group-id}</groupId>
            <artifactId>${quarkus.platform.artifact-id}</artifactId>
            <version>${quarkus.platform.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>${quarkus.platform.group-id}</groupId>
            <artifactId>quarkus-maven-plugin</artifactId>
            <version>${quarkus.platform.version}</version>
            <extensions>true</extensions>
            <executions>
                <execution>
                    <goals>
                        <goal>build</goal>
                        <goal>generate-code</goal>
                        <goal>generate-code-tests</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

在 Gradle 项目中,你会发现类似的设置:

  • the Quarkus Gradle plugin

  • 用于 Quarkus BOM 的 `enforcedPlatform`指令

如果我们关注依赖部分,你会看到允许开发 REST 应用程序的扩展:

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

The Jakarta REST resources

在项目创建过程中,已经创建了 `src/main/java/org/acme/GreetingResource.java`文件,内容如下:

package org.acme;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus REST";
    }
}

这是一个非常简单的 REST 端点,对 "/hello" 上的请求返回 "Hello from Quarkus REST"。

Differences with vanilla Jakarta REST

使用 Quarkus 时,不需要创建 Application`类。这是受支持的,但不是必需的。此外,只创建资源的一个实例,而不是每个请求一个。你可以使用不同的 `*Scoped`注释(`ApplicationScoped、`RequestScoped`等)对其进行配置。

Running the application

现在,我们可以运行应用程序了:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev
[INFO] --------------------< org.acme:getting-started >---------------------
[INFO] Building getting-started 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ getting-started ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory <path>/getting-started/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ getting-started ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to <path>/getting-started/target/classes
[INFO]
[INFO] --- quarkus-maven-plugin:<version>:dev (default-cli) @ getting-started ---
Listening for transport dt_socket at address: 5005
2019-02-28 17:05:22,347 INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
2019-02-28 17:05:22,635 INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 288ms
2019-02-28 17:05:22,770 INFO  [io.quarkus] (main) Quarkus started in 0.668s. Listening on: http://localhost:8080
2019-02-28 17:05:22,771 INFO  [io.quarkus] (main) Installed features: [cdi, rest]

一旦启动,你可以请求提供的端点:

$ curl -w "\n" http://localhost:8080/hello
Hello from Quarkus REST

按 `CTRL+C`停止应用程序,或者保持其运行并享受闪电般的热重新加载。

Automatically add newline with curl -w "\n"

我们在本例中使用 `curl -w "\n"`是为了避免你的终端打印一个 '%' 或把结果和下一个命令提示放在同一行。

Using injection

Quarkus 中的依赖注入基于 ArC,ArC 是一种基于 CDI 的依赖注入解决方案,专为 Quarkus 的架构定制。如果你不熟悉 CDI,我们建议你阅读 Introduction to CDI指南。

Quarkus 仅实现了 CDI 特性的一部分,并附有非标准特性和特定 API,你可以在 Contexts and Dependency Injection guide中了解更多关于它的信息。

ArC 作为 quarkus-rest 的依赖项附带提供,所以你已经手边有它了。

让我们修改应用程序并添加一个伴随 Bean。使用以下内容创建 `src/main/java/org/acme/GreetingService.java`文件:

package org.acme;

import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class GreetingService {

    public String greeting(String name) {
        return "hello " + name;
    }

}

编辑 `GreetingResource`类以注入 `GreetingService`并使用它创建一个新端点:

package org.acme;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @Inject
    GreetingService service;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/greeting/{name}")
    public String greeting(String name) {
        return service.greeting(name);
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus REST";
    }
}

如果你停止了应用程序(记住你不需要这样做,更改将由我们的实时重新加载特性自动部署),请使用以下命令重新启动应用程序:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

然后检查端点是否如预期的那样返回 hello quarkus

$ curl -w "\n" http://localhost:8080/hello/greeting/quarkus
hello quarkus

Development Mode

`quarkus:dev`在开发模式下运行 Quarkus。这使能了具有后台编译的实时重新加载,这意味着当你修改 Java 文件和/或资源文件并在浏览器中刷新时,这些更改将自动生效。这对资源文件(如配置属性文件)也适用。刷新浏览器将触发对工作区的扫描,并且如果检测到任何更改,Java 文件将重新编译,应用程序将重新部署;然后通过重新部署的应用程序来处理你的请求。如果编译或部署有任何问题,错误页面将通知你。

这还会在端口 5005`上侦听调试器。如果你希望在运行之前等待调试器附加,可以在命令行上传递 `-Dsuspend。如果你根本不需要调试器,可以`-Ddebug=false`。

Testing

好的,到目前为止一切顺利,但是万一进行一些测试岂不是更好?

在生成的构建文件中,你可以看到 2 个测试依赖:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <scope>test</scope>
</dependency>
build.gradle
testImplementation("io.quarkus:quarkus-junit5")
testImplementation("io.rest-assured:rest-assured")

Quarkus 支持 JUnit 5 测试。

因此,对于 Maven,必须设置 Surefire Maven Plugin 的版本,因为默认版本不支持 JUnit 5:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire-plugin.version}</version>
    <configuration>
       <systemPropertyVariables>
          <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
          <maven.home>${maven.home}</maven.home>
       </systemPropertyVariables>
    </configuration>
</plugin>

我们还设置了 java.util.logging 系统属性,以确保测试将使用正确的日志管理器和 maven.home,以确保应用 ${maven.home}/conf/settings.xml 的自定义配置(如果有)。

生成的项目包含一个简单的测试。编辑 src/test/java/org/acme/GreetingResourceTest.java 以匹配以下内容:

package org.acme;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingResourceTest {

    @Test    (1)
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)    (2)
             .body(is("Hello from Quarkus REST"));
    }

    @Test
    public void testGreetingEndpoint() {
        String uuid = UUID.randomUUID().toString();
        given()
          .pathParam("name", uuid)
          .when().get("/hello/greeting/{name}")
          .then()
            .statusCode(200)
            .body(is("hello " + uuid));
    }

}
1 通过使用 QuarkusTest 运行程序,您可以指示 JUnit 在测试之前启动应用程序。
2 检查 HTTP 响应状态代码和内容

这些测试使用 RestAssured,但请随意使用您最喜欢的库。

您可以使用 Maven 运行它们:

./mvnw test

您还可以直接从 IDE 运行测试(请确保您先停止该应用程序)。

默认情况下,测试将在端口 8081 上运行,以避免与正在运行的应用程序冲突。我们会自动配置 RestAssured 使用此端口。如果您想使用不同的客户端,则应使用 @TestHTTPResource`注释将被测试应用程序的 URL 直接注入测试类的字段中。此字段可以是 `StringURLURI 类型。还可以为此注释提供测试路径的值。例如,如果我想测试映射到 /myservlet 的 Servlet,我会将其添加到我的测试中:

@TestHTTPResource("/myservlet")
URL testUrl;

测试端口可以通过 quarkus.http.test-port 配置属性进行控制。Quarkus 还会创建一个系统属性,称为 test.url,该属性被设置为在无法使用注入的情况下的基本测试 URL。

Working with multi-module project or external modules

Quarkus 在构建时大量使用 Jandex,以发现各种类或注释。一个直接可以识别的应用程序就是 CDI Bean 发现。因此,如果此构建时发现未正确设置,则大多数 Quarkus 扩展将无法正常工作。

此索引在为其配置 Quarkus 的项目上默认创建,得益于我们的 Maven 和 Gradle 插件。

但是,在使用多模块项目时,请务必阅读 Working with multi-module projects 部分或 MavenGradle 指南。

如果您计划使用外部模块(例如,用于所有域对象的外部库),则需要通过添加 Jandex 插件(如果您能修改)或通过 quarkus.index-dependency 了解这些模块索引过程属性在您的 application.properties 中(在无法修改模块的情况下有用)。

请务必阅读 CDI 指南的 Bean Discovery 部分以获取更多信息。

Packaging and run the application

应用程序使用以下内容打包:

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

它在 /target 中生成多个输出:

  • getting-started-1.0.0-SNAPSHOT.jar - 仅包含项目的类和资源,这是 Maven 构建产生的常规工件 - 它是 not 可运行 jar;

  • 包含 quarkus-run.jar jar 文件的 quarkus-app 目录——是一个可执行 jar。请注意,它不是一个 über-jar,因为依赖项已复制到 quarkus-app/lib/ 的子目录中。

你可以使用以下命令运行应用程序: java -jar target/quarkus-app/quarkus-run.jar

如果你想在某个地方(通常在容器中)部署你的应用程序,则需要部署整个 quarkus-app 目录。

在运行应用程序之前,请不要忘记停止热重载模式(点击 CTRL+C),否则你将遇到端口冲突。

默认情况下,当 Quarkus 应用程序启动(在常规或开发模式下)时,它将显示一个 ASCII 艺术标语。可以通过设置 application.properties 中的 quarkus.banner.enabled=false,设置 -Dquarkus.banner.enabled=false Java 系统属性,或设置 QUARKUS_BANNER_ENABLED 环境变量为 false 来禁用标语。此外,用户可以通过将标语文件放在 src/main/resources 中并在 application.properties 中配置 quarkus.banner.path=name-of-file 来提供一个自定义标语。

Non Application endpoints

不同的 Quarkus 扩展为不同的类型的应用程序信息提供非应用程序端点。此类扩展的示例是 healthmetricsOpenAPI 和信息扩展。

这些非应用程序端点通常可以在 /q 前缀下访问,如以下所示:

  • /q/health

  • /q/metrics

  • /q/openapi

  • /q/info

但是,用户还可以选择将可能存在安全风险的一个端点暴露在不同的 TCP 端口下,方法是使用一个专门的 management interface

Info endpoint

如果应用程序包含 quarkus-info 扩展,则 Quarkus 默认情况下将公开 /q/info 端点,该端点提供有关构建、java 版本、版本控制和操作系统的的信息。公开信息的详细级别是可配置的。

实现 InfoContributor 的所有 CDI bean 都将被选中,并且它们的数据将附加到端点。

Configuration Reference

Unresolved include directive in modules/ROOT/pages/getting-started.adoc - include::../../../target/quarkus-generated-doc/config/quarkus-info.adoc[]

What’s next?

本指南涵盖了使用 Quarkus 创建应用程序的过程。然而,还有更多。我们建议通过创建 your second Quarkus application、并使用 dev 服务和持久性来继续此旅程。你可以了解如何创建一个本机可执行文件并使用 building a native executable guide 将它打包到容器中。如果你对反应感兴趣,我们推荐 getting started with reactive guide,在这里你可以了解如何使用 Quarkus 实现响应式应用程序。

此外,tooling guide 文档解释了如何:

  • 使用一条命令行来搭建一个项目

  • 启用 development mode (热重载)

  • 在你最喜欢的 IDE 中导入项目

  • and more