The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

连续统一体

多年来,客户端服务器(CS)架构一直是构建应用程序的事实标准。但是,一个重大的转变发生了。一种模式统治一切的时代已经过去。一系列新的应用程序和架构风格已经出现,并改变了代码的编写方式以及应用程序的部署和执行方式。HTTP微服务、响应式应用、事件驱动架构和无服务器现在是现代系统的核心角色。

Quarkus的设计考虑到了这个新的世界,并为这些不同的范式提供了一流的支持。这并不意味着你不能用Quarkus建立单体;你可以顺利地做到这一点。反而这意味着Quarkus的开发模型会变化,来适应您正在开发的应用程序的类型,单片机、微服务、响应式、事件驱动、无服务......

HTTP微服务

让我们从最基本的开始:HTTP微服务。在这种情况下,你需要开发一个HTTP端点,通常称为REST或CRUD。你处理传入的HTTP请求,而要做到这一点,你往往需要依靠其他服务,如数据库,或另一个HTTP服务。

对于这种类型的应用,Quarkus依赖于众所周知的标准,如JAX-RS、JPA和MicroProfile Rest Client,但也有Hibernate与Panache来简化与数据库的交互。

让我们来看看一个非常简单的处理周期表中元素的应用程序。代码将是这样的:

@Path("/elements")
        public class ElementResource {

    @GET
    public List<Element> getAll() {
        return Element.listAll();
    }

    @GET
    @Path("/{position}")
    public Element getOne(@PathParam("position") int position) {
        Element element = Element.find("position", position).firstResult();
        if (element == null) {
            throw new WebApplicationException("Element with position " + position + " does not exist.", 404);
        }
        return element;
    }

    @POST
    @Transactional
    public Response create(Element element) {
        element.persist();
        return Response.ok(element).status(201).build();
    }

    //...
}

如果你是一个Java EE或Spring的用户,这个开发模型应该看起来很熟悉。你暴露一个资源,其中包含有@GET, @POST...​​ 注释的方法来处理不同的请求。路径是使用@Path注解指定的。Quarkus还支持Spring控制器注释,如@GetMapping@RestController

你可以直接使用JPA实体管理器。Panache提出了一个替代方案,去掉了模板,暴露了一个活跃的记录和存储库模型。

有了Panache,Element类就会像这样简单:

@Entity
public class Element extends PanacheEntity {

    public String name;
    public String symbol;
    @Column(unique = true)
    public int position;
}

微服务往往是以系统的形式出现的。现在让我们想象一下,你需要访问另一个HTTP端点。你可以直接使用HTTP客户端;这不过是在重复模板代码。Quarkus提供了一种方法,可以使用MicroProfile Rest Client API轻松调用HTTP端点。

首先声明你的服务如下:

@Path("/elements")
@RegisterRestClient(configKey="element-service")
public interface ElementService {

    @GET
    @Path("/{position}")
    Element getElement(@PathParam("position") int position);
}

对于你打算做的每个调用,添加一个方法并使用注解来描述行为。您可以将REST客户端与容错扩展结合起来,以优雅地处理失败。然后,在你的资源中,只需使用ElementService接口:

@Path("/elem")
public class ElementResource {

    @RestClient
    ElementService elements;

    @GET
    @Path("/{position}")
    public Element name(@PathParam("position") int position) {
        return elements.getElement(position);
    }
}

但你可能想知道URL是在哪里配置的,因为它不在代码中。记住,它不能是硬编码的,因为URL很可能取决于环境。URL是在应用程序配置中设置的:

element-service/mp-rest/url=http://localhost:9001

现在可以在部署期间或在启动时使用系统属性或环境变量更新URL。

Quarkus并不局限于HTTP。您可以使用gRPCGraphQL,这是微服务领域的两个突出的替代方案。

响应式风格

在过去的几年里,应用需求发生了巨大的变化。任何应用要想在云计算、大数据或物联网时代取得成功,采取响应式的做法正日益成为应遵循的架构风格。

今天的用户接受具有几毫秒响应时间、100%正常运行时间、更低延迟、推送数据而不是拉动、更高的吞吐量和弹性的应用程序。然而,如果不对资源、基础设施和工具进行大量投资,使用昨天的软件架构几乎不可能实现这些功能。世界变了,拥有几十台服务器、较长的响应时间(>500毫秒)、因维护或瀑布式的故障而导致的停机时间,并不能满足预期的用户体验。

Quarkus可以帮助您实现响应式的旅程。Quarkus基于响应式核心,允许您的应用程序混合响应式和指令式组件。例如,您可以使用RESTEasy 响应式扩展实现响应式HTTP端点,具体如下:

@GET
@Path("/elements/{position}")
public Uni<Element> getElement(@PathParam("position") int position) {
    return elements.getElement(position)
        .onFailure().recoverWithItem(FALLBACK);
}

运用Mutiny 响应式API,你可以组成异步操作,并在不阻塞I/O线程的情况下达成一切结果。这大大改善了资源消耗和弹性。大多数Quarkus API都可以使用指令式和响应式两种方式。例如,你可以使用REST客户端的响应式版本。

@Path("/elements")
@RegisterRestClient(configKey="element-service")
public interface ElementService {

    @GET
    @Path("/{position}")
    Uni<Element> getElement(@PathParam("position") int position);
}

还有,事件流怎么处理?用Quarkus生成一个server-sent 事件响应也同样简单。

@Produces(MediaType.SERVER_SENT_EVENTS)
@GET
@Path("/events")
public Multi<String> stream() {
    return kafka.toMulti();
}

事件驱动的架构

然而,HTTP的特性禁止实现响应式系统,即所有组件都使用异步消息传递进行交互。

首先,你可以从AMQP或Apache Kafka等各种代理那里消费消息,并顺利地处理这些消息。

@ApplicationScoped
public class MyEventProcessor {

  @Incoming("health")
  @Outgoing("heartbeat")
  public double extractHeartbeat(Health health) {
    return health.getHeartbeat();
  }
}

@Incoming@Outgoing 注解是响应式消息的一部分。它们用于表达您从哪个channel消费,以及向哪个channel发送。由于响应式消息传递,您可以从不同的代理和传输工具(如HTTP、Kafka或Apache Camel)消费和发送消息。

有时你需要的不仅仅是逐一处理消息。你也可以使用响应式编程来表达消息处理逻辑,如下面的片段所示:

@Incoming("health")
@Outgoing("output")
public Multi<Record<String, Measure> filterState(Multi<Capture> input) {
    return input
        .drop().repetitions()
        .select().where(capture -> capture.value > 0)
        .onItem().transform(capture -> new Measure(capture.sensor, capture.value, capture.unit))
        .onItem().transform(measure -> Record.of(measure.sensor, measure));
}

那么Quarkus的采用Mutiny API作为响应式API来进行流操作。

函数作为服务(FaaS)和无服务(Serverless)

由于其出色的启动时间和较低的内存使用,您可以使用Quarkus实现在无服务器环境中使用的功能。Quarkus提供了Funqy,一种编写可部署到各种FaaS环境中的函数的方法,如AWS Lambda、Azure函数、Knative和Knative事件(云事件)。它也可以作为一个独立的服务使用。

Funqy函数就像是这样:

import io.quarkus.funqy.Funq;

public class GreetingFunction {
    @Funq
    public String greet(String name) {
       return "Hello " + name;
    }
}

您可以在函数中使用任何Quarkus特性,并受益于快速启动和低内存利用率。使用Quarkus,您无需改变编程语言就可以拥抱这个新世界。