RESTEasy Classic
本指南介绍的是 RESTEasy Classic,它是 Quarkus 2.8 之前的默认 Jakarta REST(前身为 JAX-RS)实现。 现在推荐使用 Quarkus REST(前身为 RESTEasy Reactive),它能同样出色地支持传统的阻塞式和响应式工作负载。 有关 Quarkus REST 的更多信息,请参阅 RESTful JSON 入门指南或 Quarkus REST 参考文档。 |
如果您需要一个基于 RESTEasy Classic 的 REST 客户端(包括对 JSON 的支持),还有另一份指南。 |
创建 Maven 项目
首先,我们需要一个新项目。使用以下命令创建一个新项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=rest-json-quickstart"
此命令将生成一个导入 RESTEasy/Jakarta REST 和 Jackson 扩展的新项目,特别是添加了以下依赖
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-jackson")
为了改善用户体验,Quarkus 注册了三个 Jackson Java 8 模块,因此您无需手动操作。 |
Quarkus 还支持 JSON-B,因此如果您更喜欢 JSON-B 而不是 Jackson,则可以创建依赖于 RESTEasy JSON-B 扩展的项目。
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用 Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=rest-json-quickstart"
此命令将生成一个导入 RESTEasy/Jakarta REST 和 JSON-B 扩展的新项目,特别是添加了以下依赖
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-jsonb")
创建第一个 JSON REST 服务
在此示例中,我们将创建一个应用程序来管理水果列表。
首先,我们创建 Fruit
bean 如下:
package org.acme.rest.json;
public class Fruit {
public String name;
public String description;
public Fruit() {
}
public Fruit(String name, String description) {
this.name = name;
this.description = description;
}
}
没什么特别的。需要注意的重要一点是,JSON 序列化层需要一个默认构造函数。
现在,创建 org.acme.rest.json.FruitResource
类如下:
package org.acme.rest.json;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
@Path("/fruits")
public class FruitResource {
private Set<Fruit> fruits = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));
public FruitResource() {
fruits.add(new Fruit("Apple", "Winter fruit"));
fruits.add(new Fruit("Pineapple", "Tropical fruit"));
}
@GET
public Set<Fruit> list() {
return fruits;
}
@POST
public Set<Fruit> add(Fruit fruit) {
fruits.add(fruit);
return fruits;
}
@DELETE
public Set<Fruit> delete(Fruit fruit) {
fruits.removeIf(existingFruit -> existingFruit.name.contentEquals(fruit.name));
return fruits;
}
}
实现非常简单,您只需使用 Jakarta REST 注释定义端点即可。
当安装了 要禁用默认的 JSON 行为,请将 如果您不依赖于 JSON 默认设置,强烈建议在端点上使用 |
配置 JSON 支持
Jackson
在 Quarkus 中,通过 CDI 获取的默认 Jackson ObjectMapper
(由 Quarkus 扩展使用)设置为忽略未知属性(通过禁用 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
)。
要恢复 Jackson 的默认行为,请在 application.properties
中将 quarkus.jackson.fail-on-unknown-properties=true
设置为 true
,或使用 @JsonIgnoreProperties(ignoreUnknown = false)
为每个类单独设置。
此外,ObjectMapper
会以 ISO-8601 格式化日期和时间(通过禁用 SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
)。
要恢复 Jackson 的默认行为,请在 application.properties
中使用 quarkus.jackson.write-dates-as-timestamps=true
。对于单个字段的自定义日期格式,请使用 @JsonFormat
注释。
Quarkus 通过 CDI bean 简化了 Jackson 的配置。创建一个类型为 io.quarkus.jackson.ObjectMapperCustomizer
的 CDI bean 来应用各种 Jackson 设置。以下是注册自定义模块的示例:
@ApplicationScoped
public class MyObjectMapperCustomizer implements ObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
// Add custom Jackson configuration here
}
}
建议使用此方法来配置 Jackson 设置。
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.jackson.ObjectMapperCustomizer;
import jakarta.inject.Singleton;
@Singleton
public class RegisterCustomModuleCustomizer implements ObjectMapperCustomizer {
public void customize(ObjectMapper mapper) {
mapper.registerModule(new CustomModule());
}
}
用户甚至可以选择提供自己的 ObjectMapper
bean。如果这样做,请务必在生成 ObjectMapper
的 CDI producer 中手动注入并应用所有 io.quarkus.jackson.ObjectMapperCustomizer
bean。否则,将无法应用各种扩展提供的 Jackson 特定自定义。
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.arc.All;
import io.quarkus.jackson.ObjectMapperCustomizer;
import java.util.List;
import jakarta.inject.Singleton;
public class CustomObjectMapper {
// Replaces the CDI producer for ObjectMapper built into Quarkus
@Singleton
ObjectMapper objectMapper(@All List<ObjectMapperCustomizer> customizers) {
ObjectMapper mapper = myObjectMapper(); // Custom `ObjectMapper`
// Apply all ObjectMapperCustomizer beans (incl. Quarkus)
for (ObjectMapperCustomizer customizer : customizers) {
customizer.customize(mapper);
}
return mapper;
}
}
JSON-B
如上所述,Quarkus 通过使用 quarkus-resteasy-jsonb
扩展提供了使用 JSON-B 而不是 Jackson 的选项。
遵循与上一节中描述的相同方法,可以使用 io.quarkus.jsonb.JsonbConfigCustomizer
bean 来配置 JSON-B。
例如,如果需要为类型 com.example.Foo
注册一个名为 FooSerializer
的自定义序列化器,添加如下 bean 即可:
import io.quarkus.jsonb.JsonbConfigCustomizer;
import jakarta.inject.Singleton;
import jakarta.json.bind.JsonbConfig;
import jakarta.json.bind.serializer.JsonbSerializer;
@Singleton
public class FooSerializerRegistrationCustomizer implements JsonbConfigCustomizer {
public void customize(JsonbConfig config) {
config.withSerializers(new FooSerializer());
}
}
更高级的选项是直接提供一个 jakarta.json.bind.JsonbConfig
bean(作用域为 Dependent
),或者在极端情况下,提供一个 jakarta.json.bind.Jsonb
类型的 bean(作用域为 Singleton
)。如果采用后一种方法,请务必在生成 jakarta.json.bind.Jsonb
的 CDI producer 中手动注入并应用所有 io.quarkus.jsonb.JsonbConfigCustomizer
bean。否则,将无法应用各种扩展提供的 JSON-B 特定自定义。
import io.quarkus.jsonb.JsonbConfigCustomizer;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Instance;
import jakarta.json.bind.JsonbConfig;
public class CustomJsonbConfig {
// Replaces the CDI producer for JsonbConfig built into Quarkus
@Dependent
JsonbConfig jsonConfig(Instance<JsonbConfigCustomizer> customizers) {
JsonbConfig config = myJsonbConfig(); // Custom `JsonbConfig`
// Apply all JsonbConfigCustomizer beans (incl. Quarkus)
for (JsonbConfigCustomizer customizer : customizers) {
customizer.customize(config);
}
return config;
}
}
JSON 超文本应用语言 (HAL) 支持
HAL 标准是一种表示 Web 链接的简单格式。
要启用 HAL 支持,请将 quarkus-hal
扩展添加到您的项目中。此外,由于 HAL 需要 JSON 支持,您需要添加 quarkus-resteasy-jsonb
或 quarkus-resteasy-jackson
扩展。
GAV | 用法 |
---|---|
|
添加扩展后,我们现在可以注解 REST 资源以生成媒体类型 application/hal+json
(或使用 RestMediaType.APPLICATION_HAL_JSON)。例如:
@Path("/records")
public class RecordsResource {
@GET
@Produces({ MediaType.APPLICATION_JSON, "application/hal+json" })
@LinkResource(entityClassName = "org.acme.Record", rel = "list")
public List<TestRecord> getAll() {
// ...
}
@GET
@Path("/first")
@Produces({ MediaType.APPLICATION_JSON, "application/hal+json" })
@LinkResource(rel = "first")
public TestRecord getFirst() {
// ...
}
}
现在,端点 /records
和 /records/first
将接受 json
和 hal+json
媒体类型,以 HAL 格式打印记录。
例如,如果我们使用 curl 调用 /records
端点以返回记录列表,HAL 格式将如下所示:
& curl -H "Accept:application/hal+json" -i localhost:8080/records
{
"_embedded": {
"items": [
{
"id": 1,
"slug": "first",
"value": "First value",
"_links": {
"list": {
"href": "https://:8081/records"
},
"first": {
"href": "https://:8081/records/first"
}
}
},
{
"id": 2,
"slug": "second",
"value": "Second value",
"_links": {
"list": {
"href": "https://:8081/records"
},
"first": {
"href": "https://:8081/records/first"
}
}
}
]
},
"_links": {
"list": {
"href": "https://:8081/records"
}
}
}
当我们调用返回单个实例的资源 /records/first
时,输出是:
& curl -H "Accept:application/hal+json" -i localhost:8080/records/first
{
"id": 1,
"slug": "first",
"value": "First value",
"_links": {
"list": {
"href": "https://:8081/records"
},
"first": {
"href": "https://:8081/records/first"
}
}
}
创建一个前端
现在,让我们添加一个简单的网页来与我们的 FruitResource
进行交互。Quarkus 会自动服务位于 META-INF/resources
目录下的静态资源。在 src/main/resources/META-INF/resources
目录中,添加一个 fruits.html
文件,其中包含此 fruits.html 文件中的内容。
您现在可以与您的 REST 服务交互
-
使用以下命令启动 Quarkus
CLIquarkus dev
Maven./mvnw quarkus:dev
Gradle./gradlew --console=plain quarkusDev
-
打开浏览器访问
https://:8080/fruits.html
-
通过表单将新水果添加到列表中
构建本机可执行文件
您可以使用常用命令构建本机可执行文件
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
运行它就像执行 ./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner
一样简单。
然后,您可以将您的浏览器指向 https://:8080/fruits.html
并使用您的应用程序。
关于序列化
JSON 序列化库使用 Java 反射来获取对象的属性并进行序列化。
当使用 GraalVM 的原生可执行文件时,所有将用于反射的类都需要被注册。好消息是 Quarkus 大部分时间都会为您处理这项工作。到目前为止,我们还没有为反射使用注册任何类,甚至没有注册 Fruit
,一切都运行正常。
当 Quarkus 能够从 REST 方法推断出序列化的类型时,它会执行一些魔法。当您拥有以下 REST 方法时,Quarkus 会确定 Fruit
将被序列化:
@GET
public List<Fruit> list() {
// ...
}
Quarkus 会在构建时通过分析 REST 方法自动为您完成这些操作,这就是为什么在本指南的第一部分我们不需要任何反射注册。
Jakarta REST 世界中的另一个常见模式是使用 Response
对象。Response
附带一些很好的优点:
-
您可以根据方法中的情况返回不同的实体类型(例如
Legume
或Error
)。 -
您可以设置
Response
的属性(错误情况下的状态码)。
您的 REST 方法将如下所示:
@GET
public Response list() {
// ...
}
Quarkus 在构建时无法确定 Response
中包含的类型,因为信息不可用。在这种情况下,Quarkus 将无法自动注册所需类的反射。
这就引出了我们的下一部分。
使用 Response
让我们创建 Legume
类,它将作为 JSON 序列化,遵循与我们的 Fruit
类相同的模型:
package org.acme.rest.json;
public class Legume {
public String name;
public String description;
public Legume() {
}
public Legume(String name, String description) {
this.name = name;
this.description = description;
}
}
现在让我们创建一个 LegumeResource
REST 服务,其中只有一个方法可以返回豆类列表。
此方法返回一个 Response
而不是 Legume
列表。
package org.acme.rest.json;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/legumes")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class LegumeResource {
private Set<Legume> legumes = Collections.synchronizedSet(new LinkedHashSet<>());
public LegumeResource() {
legumes.add(new Legume("Carrot", "Root vegetable, usually orange"));
legumes.add(new Legume("Zucchini", "Summer squash"));
}
@GET
public Response list() {
return Response.ok(legumes).build();
}
}
现在,让我们添加一个简单的网页来显示我们的豆类列表。在 src/main/resources/META-INF/resources
目录中,添加一个 legumes.html
文件,其中包含此 legumes.html 文件中的内容。
在浏览器中打开 https://:8080/legumes.html,您将看到我们的豆类列表。
当将应用程序作为原生可执行文件运行时,有趣的部分就开始了。
-
使用以下命令创建原生可执行文件:
CLIquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
使用
./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner
执行它。 -
打开浏览器并转到 https://:8080/legumes.html。
那里没有豆类。
如上所述,问题在于 Quarkus 无法确定 Legume
类,该类需要通过分析 REST 端点来进行一些反射。JSON 序列化库尝试获取 Legume
的字段列表,但得到一个空列表,因此它不会序列化字段数据。
目前,当 JSON-B 或 Jackson 尝试获取类的字段列表时,如果类未注册用于反射,则不会抛出异常。GraalVM 将返回一个空字段列表。 希望将来会有所改变,使错误更加明显。 |
我们可以通过在 Legume
类上添加 @RegisterForReflection
注释来手动注册 Legume
进行反射。
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection
public class Legume {
// ...
}
@RegisterForReflection 注释指示 Quarkus 在原生编译期间保留该类及其成员。有关 @RegisterForReflection 注释的更多详细信息,请参阅 原生应用程序提示页面。 |
让我们这样做,并遵循与之前相同的步骤:
-
按
Ctrl+C
停止应用程序。 -
使用以下命令创建原生可执行文件:
CLIquarkus build --native
Maven./mvnw install -Dnative
Gradle./gradlew build -Dquarkus.native.enabled=true
-
使用
./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner
执行它。 -
打开浏览器并转到 https://:8080/legumes.html。
这次,您可以看到我们的豆类列表。
响应式编程
对于响应式工作负载,请始终使用 Quarkus REST。 |
您可以返回*响应式类型*来处理异步处理。Quarkus 推荐使用 Mutiny 来编写响应式和异步代码。
要集成 Mutiny 和 RESTEasy,您需要将 quarkus-resteasy-mutiny
依赖添加到您的项目中:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-mutiny</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-mutiny")
然后,您的端点可以返回 Uni
或 Multi
实例:
@GET
@Path("/{name}")
public Uni<Fruit> getOne(@PathParam String name) {
return findByName(name);
}
@GET
public Multi<Fruit> getAll() {
return findAll();
}
当您有一个单个结果时,使用 Uni
。当您有多个可能异步发出的项时,使用 Multi
。
您可以使用 Uni
和 Response
返回异步 HTTP 响应:Uni<Response>
。
有关 Mutiny 的更多详细信息,请参阅 Mutiny - 直观的响应式编程库。
HTTP 过滤器和拦截器
可以通过提供相应的 ContainerRequestFilter
或 ContainerResponseFilter
实现来拦截 HTTP 请求和响应。这些过滤器适用于处理与消息相关的元数据:HTTP 头、查询参数、媒体类型和其他元数据。它们还可以中止请求处理,例如,当用户没有权限访问端点时。
让我们使用 ContainerRequestFilter
为我们的服务添加日志记录功能。我们可以通过实现 ContainerRequestFilter
并用 @Provider
注释来完成此操作:
package org.acme.rest.json;
import io.vertx.core.http.HttpServerRequest;
import org.jboss.logging.Logger;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.Provider;
@Provider
public class LoggingFilter implements ContainerRequestFilter {
private static final Logger LOG = Logger.getLogger(LoggingFilter.class);
@Context
UriInfo info;
@Context
HttpServerRequest request;
@Override
public void filter(ContainerRequestContext context) {
final String method = context.getMethod();
final String path = info.getPath();
final String address = request.remoteAddress().toString();
LOG.infof("Request %s %s from IP %s", method, path, address);
}
}
现在,每当调用 REST 方法时,请求都会被记录到控制台。
2019-06-05 12:44:26,526 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /legumes from IP 127.0.0.1
2019-06-05 12:49:19,623 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /fruits from IP 0:0:0:0:0:0:0:1
2019-06-05 12:50:44,019 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request POST /fruits from IP 0:0:0:0:0:0:0:1
2019-06-05 12:51:04,485 INFO [org.acm.res.jso.LoggingFilter] (executor-thread-1) Request GET /fruits from IP 127.0.0.1
GZip 支持
Quarkus 带有 GZip 支持(尽管默认情况下未启用)。以下配置选项允许配置 GZip 支持。
quarkus.resteasy.gzip.enabled=true (1)
quarkus.resteasy.gzip.max-input=10M (2)
1 | 启用 Gzip 支持。 |
2 | 配置压缩请求体的上限。这有助于通过限制其范围来减轻潜在攻击。默认值为 10M 。此配置选项可以识别以下格式的字符串(显示为正则表达式):[0-9]+[KkMmGgTtPpEeZzYy]? 。如果未给出后缀,则假定为字节。 |
一旦启用了 GZip 支持,您可以通过将 @org.jboss.resteasy.annotations.GZIP
注释添加到您的端点方法来在端点上使用它。
还有一个 quarkus.http.enable-compression 配置属性,它全局启用 HTTP 响应压缩。如果启用,当 Content-Type HTTP 头被设置,并且其值是根据 quarkus.http.compress-media-types 配置属性配置的压缩媒体类型时,响应体将被压缩。 |
Multipart 支持
RESTEasy 通过 RESTEasy Multipart Provider 支持 multipart。
Quarkus 提供了一个名为 quarkus-resteasy-multipart
的扩展,让您的工作更轻松。
此扩展与 RESTEasy 的默认行为略有不同,因为默认字符集(如果请求中未指定)是 UTF-8,而不是 US-ASCII。
您可以使用以下配置属性配置此行为:
构建时固定的配置属性 - 所有其他配置属性都可以在运行时覆盖
配置属性 |
类型 |
默认 |
---|---|---|
默认字符集。 请注意,默认值是 UTF-8,这与 RESTEasy 的默认值 US-ASCII 不同。 环境变量: 显示更多 |
|
|
默认内容类型。 环境变量: 显示更多 |
字符串 |
|
Servlet 兼容性
在 Quarkus 中,RESTEasy 可以直接运行在 Vert.x HTTP 服务器之上,或者如果您有任何 Servlet 依赖,则可以运行在 Undertow 之上。
因此,某些类,例如 HttpServletRequest
,并不总是可用于注入。此特定类的多数用例都有 Jakarta REST 等效项,但获取远程客户端 IP 除外。
RESTEasy 提供了一个您可以注入的替代 API:HttpRequest
,它具有 getRemoteAddress()
和 getRemoteHost()
方法来解决此问题。
RESTEasy 和 REST Client 交互
在 Quarkus 中,RESTEasy 扩展和 REST Client 扩展共享相同的底层基础。一个重要的结果是它们共享相同的提供程序列表(在 Jakarta REST 的意义上)。
例如,如果您声明了一个 WriterInterceptor
,它默认会拦截服务器调用和客户端调用,这可能不是期望的行为。
但是,您可以通过添加 @ConstrainedTo(RuntimeType.CLIENT)
注释到提供程序来更改此默认行为并限制提供程序:
-
仅考虑*服务器*调用,方法是在您的提供程序上添加
@ConstrainedTo(RuntimeType.SERVER)
注释; -
仅考虑*客户端*调用,方法是在您的提供程序上添加
@ConstrainedTo(RuntimeType.CLIENT)
注释。
与 Jakarta EE 开发的区别
仅一个 Jakarta REST 应用程序
与在标准 Servlet 容器中运行的 Jakarta REST(和 RESTEasy)不同,Quarkus 只支持部署一个 Jakarta REST 应用程序。如果定义了多个 Jakarta REST Application
类,构建将失败并显示消息 Multiple classes have been annotated with @ApplicationPath which is currently not supported
。
如果定义了多个 Jakarta REST 应用程序,可以使用属性 quarkus.resteasy.ignore-application-classes=true
来忽略所有显式的 Application
类。这使得所有资源类都可以通过 quarkus.resteasy.path
(默认为 /
)定义的应用程序路径进行访问。
Jakarta REST 应用程序的支持限制
RESTEasy 扩展不支持 jakarta.ws.rs.core.Application
类的 getProperties()
方法。此外,它仅依赖于 getClasses()
和 getSingletons()
方法来过滤带注释的资源、提供程序和功能类。它不会过滤内置的资源、提供程序和功能类,也不会过滤其他扩展注册的资源、提供程序和功能类。最后,getSingletons()
方法返回的对象被忽略,只考虑类来过滤资源、提供程序和功能类,换句话说,getSingletons()
方法与 getClasses()
的处理方式相同。
资源生命周期
在 Quarkus 中,所有 Jakarta REST 资源都被视为 CDI Bean。可以通过 @Inject
注入其他 Bean,使用 @Transactional
等绑定注入拦截器,定义 @PostConstruct
回调等。
如果在资源类上未声明作用域注释,则作用域将默认为。quarkus.resteasy.singleton-resources
属性可以控制默认作用域。
如果设置为 true
(默认值),则会创建一个资源类的*单个实例*来服务所有请求(如 @jakarta.inject.Singleton
所定义的)。
如果设置为 false
,则为每个请求创建一个资源类的*新实例*。
显式的 CDI 作用域注释(@RequestScoped
、@ApplicationScoped
等)始终会覆盖默认行为,并指定资源实例的生命周期。
|
使用构建时条件包含/排除 Jakarta REST 类
Quarkus 允许直接通过构建时条件包含或排除 Jakarta REST 资源、提供程序和功能,就像它为 CDI Bean 所做的那样。因此,各种 Jakarta REST 类可以被注解上配置文件条件(@io.quarkus.arc.profile.IfBuildProfile
或 @io.quarkus.arc.profile.UnlessBuildProfile
)和/或属性条件(io.quarkus.arc.properties.IfBuildProperty
或 io.quarkus.arc.properties.UnlessBuildProperty
),以便在构建时指示 Quarkus 在什么条件下应该包含这些 Jakarta REST 类。
在下面的示例中,Quarkus 将包含 sayHello
端点,当且仅当启用了构建配置文件 app1
。
@IfBuildProfile("app1")
public class ResourceForApp1Only {
@GET
@Path("sayHello")
public String sayHello() {
return "hello";
}
}
请注意,如果检测到 Jakarta REST 应用程序并且重写了 getClasses()
和/或 getSingletons()
方法,Quarkus 将忽略构建时条件,并且只考虑 Jakarta REST 应用程序中定义的内容。