RESTEasy Classic
本指南关于 RESTEasy Classic,它曾经是 Quarkus 2.8 之前的默认 Jakarta REST(以前称为 JAX-RS)实现。 现在建议使用 Quarkus REST(以前称为 RESTEasy Reactive),它对传统阻塞工作负载和响应式工作负载提供同样出色的支持。 有关 Quarkus REST 的更多信息,请参阅 introductory REST JSON guide 或 Quarkus REST reference documentation。
如果您需要 REST client based on RESTEasy Classic,还有另一本指南(包括对 JSON 的支持)。 |
- Architecture
- Creating the Maven project
- Creating the first JSON REST service
- Creating a frontend
- Building a native executable
- About serialization
- Using response
- Being reactive
- HTTP filters and interceptors
- CORS filter
- GZip Support
- Multipart Support
- Servlet compatibility
- RESTEasy and REST Client interactions
- What’s Different from Jakarta EE Development
- Include/Exclude Jakarta REST classes with build time conditions
- Conclusion
Creating the Maven project
首先,我们需要一个新项目。使用以下命令创建一个新项目:
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 指南。
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}"
此命令生成一个导入 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 modules,因此您无需手动进行此操作。 |
Quarkus 还支持 JSON-B,因此,如果您更喜欢 JSON-B 而不是 Jackson,则可以创建依赖于 RESTEasy JSON-B 扩展的项目:
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 指南。
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}"
此命令生成一个导入 RESTEasy/Jakarta REST 和 JSON-B 扩展的新项目,特别添加了以下依赖项:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-jsonb")
Creating the first JSON REST service
在此示例中,我们将创建一个应用程序来管理水果列表。
首先,让我们按如下方式创建 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 注解定义您的端点。
当安装了如 |
Configuring JSON support
Jackson
在 Quarkus 中,通过 CDI(由 Quarkus 扩展使用)获得的默认 Jackson ObjectMapper
设置为忽略未知属性(通过禁用 DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
)。
若要恢复 Jackson 的默认行为,请在 application.properties
中设置 quarkus.jackson.fail-on-unknown-properties=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 产生器中应用所有 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。
例如,如果需要使用 JSON-B 注册名为 FooSerializer
的类型 com.example.Foo
的自定义序列化程序,则只需添加如下所示的 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
(拥有 Dependent
作用域)bean,或者在极端情况下,提供一个类型为 jakarta.json.bind.Jsonb
(拥有 Singleton
作用域)的 bean。如果使用后一种方法,则非常重要的手动注入并应用 CDI 生成器中生成 jakarta.json.bind.Jsonb
的所有 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 Hypertext Application Language (HAL) support
HAL 标准是用于表示 Web 链接的简单格式。
要启用 HAL 支持,请将 quarkus-hal
扩展添加到您的项目。此外,由于 HAL 需要 JSON 支持,因此您需要添加 quarkus-resteasy-jsonb
或 quarkus-resteasy-jackson
扩展。
GAV | Usage |
---|---|
|
添加扩展后,我们现在可以对 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": "http://localhost:8081/records"
},
"first": {
"href": "http://localhost:8081/records/first"
}
}
},
{
"id": 2,
"slug": "second",
"value": "Second value",
"_links": {
"list": {
"href": "http://localhost:8081/records"
},
"first": {
"href": "http://localhost:8081/records/first"
}
}
}
]
},
"_links": {
"list": {
"href": "http://localhost: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": "http://localhost:8081/records"
},
"first": {
"href": "http://localhost:8081/records/first"
}
}
}
Creating a frontend
现在让我们添加一个简单的网页来与我们的 FruitResource
交互。Quarkus 自动提供位于 META-INF/resources
目录下的静态资源。在 src/main/resources/META-INF/resources
目录中,添加一个 fruits.html
文件,其中包含来自该 fruits.html 文件的内容。
你现在可以与你的 REST 服务进行交互:
-
start Quarkus with:include::./_includes/devtools/dev.adoc[]
-
通过表单向列表中添加新水果
Building a native executable
您可以使用以下常用命令构建一个本机可执行文件:
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
运行它与执行 ./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner
一样简单。
然后您可以将浏览器指向 http://localhost:8080/fruits.html
,并使用您的应用程序。
About serialization
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 将无法自动注册所需的类中的反射。
这将我们带到下一部分。
Using 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
文件,其中包含来自此 $${quickstarts-base-url}/blob/main/rest-json-quickstart/src/main/resources/META-INF/resources/legumes.html [legumes.html] 文件的内容。
打开一个浏览器到 [role="bare"][role="bare"]http://localhost:8080/legumes.html,您将看到我们的豆类列表。
当以本地可执行文件方式运行应用程序时,就会开始有趣的部分:
-
使用以下命令创建本地可执行文件:include::./_includes/devtools/build-native.adoc[]
-
execute it with
./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner
-
打开浏览器并转到 [role="bare"][role="bare"]http://localhost:8080/legumes.html
那里没有豆类。
如上所述,问题在于 Quarkus 无法通过分析 REST 端点来确定 Legume
类,它将需要一些反射。JSON 序列化库尝试获取 Legume
字段的列表并获取一个空列表,因此它不会序列化字段数据。
目前,当 JSON-B 或 Jackson 尝试获取某个类的字段列表时,如果未注册类以进行反射,则不会引发异常。GraalVM 将返回一个空的字段列表。 希望将来会改变这种情况,并使错误更明显。 |
我们可以通过在 Legume
类中添加 @RegisterForReflection
注解手动注册 Legume
以进行反射:
import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection
public class Legume {
// ...
}
|
让我们执行该操作,并按照之前相同的步骤进行:
-
点击
Ctrl+C
以停止应用程序 -
使用以下命令创建本地可执行文件:include::./_includes/devtools/build-native.adoc[]
-
execute it with
./target/rest-json-quickstart-1.0.0-SNAPSHOT-runner
-
打开浏览器并转到 [role="bare"][role="bare"]http://localhost:8080/legumes.html
这一次,你可以看到我们的豆类列表。
Being reactive
对于反应性工作负载,请始终使用 Quarkus REST。
你可以返回 reactive types 以处理异步处理。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 - an intuitive reactive programming library 中找到有关 Mutiny 的更多详细信息。
HTTP filters and interceptors
可以通过分别提供 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
CORS filter
Cross-origin resource sharing (CORS)是一种机制,可以通过第一个资源提供的域之外的其他域请求网页上受限的资源。
Quarkus 在 HTTP 层级别包含了一个 CORS 过滤器。有关 CORS 过滤器及其用法的更多信息,请参阅 Quarkus “跨源资源共享”指南的 CORS filter 部分。
GZip Support
Quarkus 附带 GZip 支持(尽管默认情况下未启用)。以下配置控件允许配置 GZip 支持。
quarkus.resteasy.gzip.enabled=true (1)
quarkus.resteasy.gzip.max-input=10M (2)
1 | Enable Gzip support. |
2 | 配置压缩请求正文的上限。这对于通过限制其作用范围来减轻潜在攻击非常有用。默认值为 10M 。此配置选项将识别此格式的字符串(显示为正则表达式):[0-9]+[KkMmGgTtPpEeZzYy]? 。如果没有给定后缀,则假设字节。 |
启用 GZip 支持后,您可以通过将 @org.jboss.resteasy.annotations.GZIP
注释添加到终结点方法来在终结点上使用它。
还有一个 |
Multipart Support
RESTEasy 通过 RESTEasy Multipart Provider 支持多部分。
Quarkus 提供了一个名为 quarkus-resteasy-multipart
的扩展,以便为您简化操作。
此扩展与 RESTEasy 默认行为略有不同,因为默认字符集(如果您的请求中未指定任何字符集)是 UTF-8 而不是 US-ASCII。
您可以使用以下配置属性配置此行为:
Unresolved include directive in modules/ROOT/pages/resteasy.adoc - include::../../../target/quarkus-generated-doc/config/quarkus-resteasy-multipart.adoc[]
Servlet compatibility
在 Quarkus 中,RESTEasy 既可以在 Vert.x HTTP 服务器上直接运行,也可以在任何 servlet 依赖上运行 Undertow。
因此,某些类,例如 HttpServletRequest
不总是可用于注入。对于此特定类的多数用例,除了获取远程客户端的 IP,Jakarta REST 等价项涵盖了这些用例。
RESTEasy 提供了一个替换的 API,您可以注入它: HttpRequest
,它包含方法 getRemoteAddress()
和 getRemoteHost()
来解决此问题。
RESTEasy and REST Client interactions
在 Quarkus 中,RESTEasy 扩展和 the REST Client extension 共享相同的基础结构。此考虑事项的一个重要后果是它们共享相同的提供程序列表(在 Jakarta REST 的含义中)。
例如,如果您声明一个 WriterInterceptor
,默认情况下,它将拦截服务器调用和客户端调用,而这可能不是所需的行为。
但是,您可以更改此默认行为,并将一个提供程序约束为:
-
通过向您的提供程序添加
@ConstrainedTo(RuntimeType.SERVER)
注释来仅考虑 server 调用; -
通过向您的提供程序添加
@ConstrainedTo(RuntimeType.CLIENT)
注释来仅考虑 client 调用。
What’s Different from Jakarta EE Development
Only a single Jakarta REST application
与运行于标准 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
定义的应用路径访问(默认: /
)。
Support limitations of Jakarta REST application
RESTEasy 扩展不支持类 jakarta.ws.rs.core.Application
的方法 getProperties()
。此外,它仅依赖方法 getClasses()
和 getSingletons()
过滤带注释的资源、提供程序和特性类。它不会过滤内置资源、提供程序和特性类以及其他扩展注册的资源、提供程序和特性类。最后,会忽略方法 getSingletons()
返回的对象,仅考虑这些类来过滤资源、提供程序和特性类,换句话说,方法 getSingletons()
的管理方式与 getClasses()
相同。
Lifecycle of Resources
在 Quarkus 中,所有 Jakarta REST 资源都被视为 CDI bean。可能通过 @Inject
注入其他 bean,使用如 @Transactional
这样的绑定绑定拦截器,定义 @PostConstruct
回调等。
如果没有在资源类上声明作用域注释,则该作用域将默认为该作用域。属性 quarkus.resteasy.singleton-resources
可以控制默认作用域。
如果设置成 true
(默认),则会创建一个资源类的 single instance 来服务所有请求(如 @jakarta.inject.Singleton
所定义)。
如果设置成 false
,则会为每个请求创建一个资源类的 new instance。
显式的 CDI 作用域注释(@RequestScoped
、@ApplicationScoped
等)始终覆盖默认行为并指定资源实例的生命周期。
Include/Exclude Jakarta REST classes with build time conditions
借助于构建时间条件(与 CDI bean 中的情况相同),Quarkus 能够直接包含或排除 Jakarta REST 资源、提供程序和功能。因此,可以使用配置文件条件 (@io.quarkus.arc.profile.IfBuildProfile
或 @io.quarkus.arc.profile.UnlessBuildProfile
) 和/或属性条件 (io.quarkus.arc.properties.IfBuildProperty
或 io.quarkus.arc.properties.UnlessBuildProperty
) 对各种 Jakarta REST 类进行注释,以便在构建期间向 Quarkus 指示应包含哪些 Jakarta REST 类。
在以下示例中,Quarkus 仅当启用了构建配置文件 app1
时,才会包含端点 sayHello
。
@IfBuildProfile("app1")
public class ResourceForApp1Only {
@GET
@Path("sayHello")
public String sayHello() {
return "hello";
}
}
请注意,如果已检测到 Jakarta REST 应用程序并且已覆盖了 getClasses()
和/或 getSingletons()
方法,Quarkus 将忽略构建时间条件,并且仅考虑在 Jakarta REST 应用程序中定义的内容。