连续统一体
多年来,客户端服务器(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。您可以使用gRPC或GraphQL,这是微服务领域的两个突出的替代方案。
响应式风格
在过去的几年里,应用需求发生了巨大的变化。任何应用要想在云计算、大数据或物联网时代取得成功,采取响应式的做法正日益成为应遵循的架构风格。
今天的用户接受具有几毫秒响应时间、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,您无需改变编程语言就可以拥抱这个新世界。