多功能性

多年来,客户端-服务器架构一直是构建应用程序的事实标准。但是发生了一个重大转变。一个模型统治一切的时代已经结束。一种新的应用程序和架构风格涌现出来,改变了代码的编写方式以及应用程序的部署和执行方式。HTTP 微服务、响应式应用程序、事件驱动架构、函数即服务和 AI 注入应用程序现在是现代系统中的核心参与者。

Quarkus 的设计考虑了这一新世界,并为这些范例提供了一流的支持。这并不意味着您不能使用 Quarkus 构建单体应用;您可以顺利地做到这一点。相反,这意味着 Quarkus 开发模型会变形以适应您正在开发的应用程序类型:单体应用、微服务、CLI、事件驱动应用程序、函数、Kubernetes 操作符……

HTTP 微服务

让我们从基础开始:HTTP 微服务。您需要开发一个 HTTP 端点,通常称为 REST。您处理传入的 HTTP 请求,为此,您通常需要依赖其他服务,例如数据库或其他 HTTP 服务。让我们以一个处理来自 元素周期表元素的非常简单的应用程序为例。

使用带有 Panache 的 Quarkus REST 和 Hibernate ORM,代码将如下所示

使用 Quarkus REST
@Path("/elements")
public class ElementResource {

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

   @GET
   @Path("/{position}")
   public Element getOne(int position) {
       Element element = Element.find("position",
             position).firstResult();
       if (element == null) {
           throw  new NotFoundException();
       }
       return element;
   }

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

   //...
}
使用 Spring MVC 兼容层
@RestController
public class ElementController {


   @GetMapping("/elements")
   public List<Element> getAll() {
       return Element.listAll();
   }


   @GetMapping("/elements/{position}")
   public Element getOne(int position) {
       Element element = Element.find("position",
             position).firstResult();
       if (element == null) {
           throw new ResponseStatusException(NOT_FOUND);
       }
       return element;
   }


   @PostMapping("/elements")
   @Transactional
   public Response create(Element element) {
       element.persist();
       return Response.ok(element).status(201).build();
   }


   //...
}

如果您是 Java EE 或 Spring 用户,此开发模型应该看起来很熟悉。您公开一个资源,其中包含使用 @GET@POST 注释的方法来处理不同的请求。Quarkus 还提出了一个与 Spring API 的兼容层,因此您也可以使用 @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 端点的方法。首先,按如下方式声明您的服务

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

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

只需添加一个方法并使用注释来描述您打算执行的每个调用的行为。然后,在您的资源/控制器中,只需使用 ElementService 接口

@RestClient ElementService service;
public void invokeRemoteService() {
   Element element = service.getElement(1);
}

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

quarkus.rest-client.element-service.url=https://:9001

URL 可以在部署期间或启动时使用系统属性或环境变量进行更新。您甚至可以使用 服务发现和选择。Quarkus 不仅限于 HTTP。您可以使用 gRPCGraphQL,这是微服务领域中两个突出的替代方案。

响应式

在过去的几年里,应用程序需求发生了巨大的变化。响应式架构正日益成为任何应用程序在云计算、大数据或物联网时代取得成功的首选方法。今天的用户喜欢具有毫秒级响应时间、100% 正常运行时间、更低延迟、推送数据而不是拉取数据、更高吞吐量、弹性以及可伸缩性的应用程序。然而,如果不大量投资于资源、基础设施和工具,几乎不可能使用昨天的软件架构来实现这些特性。世界已经改变,拥有数十台服务器、较长的响应时间(> 500 毫秒)以及由于维护或瀑布式故障导致的停机时间不符合预期的用户体验。我们需要构建更好的分布式系统,这就是响应式系统的座右铭。

Quarkus 可帮助您构建响应式系统。Quarkus 基于 响应式核心。每个 Quarkus 应用程序都是一个响应式应用程序。它可以有效地使用系统资源,并且可以处理大量的吞吐量。但是,您的代码不必使用响应式编程。您可以混合和匹配三种替代方案:纯命令式代码、使用虚拟线程的命令式代码或响应式代码。根据您的要求,您将选择一种或另一种,甚至混合使用它们。

命令式
@Path("/elements")
public class ElementResource {

   @GET
   public List<Element> getAll() {
       return Element.listAll();
   }
}
响应式
@Path("/elements")
public class ReactiveElementResource {

   @Inject
   ElementRepository repository;

   @GET
   public Uni<List<Element>> getAll() {
       return repository.listAll();
   }
}
虚拟线程
@Path("/elements")
@RunOnVirtualThread
public class ElementResource {

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

事件驱动架构

然而,HTTP 特性禁止实施完全 响应式系统,其中所有组件都使用异步消息传递进行交互。您可以从各种代理(例如 Apache Kafka、Apache Pulsar 或 RabbitMQ)使用消息,并顺利地处理这些消息

@ApplicationScoped
public class MeasurementProcessor {

   @Inject
   LocationRepository repository;

   @Incoming("raw-measurement")
   @Outgoing("temperatures")
   public Record<String, Temperature> process(Measurement m) {
       var location = repository
               .getLocationForDevice(m.device());
       var outcome = new Temperature(location, m.temp());
       return Record.of(location, outcome);
   }

}

@Incoming@Outgoing 注释是 Reactive Messaging 的一部分。它们用于表达您正在使用的通道和您正在发送到的通道。感谢 SmallRye Reactive Messaging,您可以从不同代理和传输(例如 HTTP、Pulsar、Kafka、RabbitMQ、JMS 或 Apache Camel)发送和接收消息。

如上所述,您可以从三种执行模型中进行选择:命令式(如上所示)、响应式(使用 Mutiny API,包括流操作)或虚拟线程

命令式消息处理
@Incoming("raw-measurement")
@Outgoing("temperatures")
public Record<String, Temperature> process(Measurement m) {
   var location = repository
           .getLocationForDevice(m.device());
   var outcome = new Temperature(location, m.temp());
   return Record.of(location, outcome);
}
响应式消息处理
@Incoming("raw-measurement")
@Outgoing("temperatures")
public Uni<Record<String, Temperature>> process(Measurement m) {
   return repository.getLocationForDevice(m.device())
           .map(location -> Record.of(location,
                   new Temperature(location, m.temp())
           ));
}
流处理
@Incoming("raw-measurement")
@Outgoing("temperatures")
public Multi<Record<String, Temperature>> transform(Multi<Measurement> stream) {
   return stream
           .onItem().transformToUniAndMerge(m ->
             repository.getLocationForDevice(m.device())
                 .map(location -> Record.of(location,
                   new Temperature(location, m.temp())
                 )
             )
       );
}
使用虚拟线程的消息处理
@Incoming("raw-measurement")
@Outgoing("temperatures")
@RunOnVirtualThread
public Record<String, Temperature> process(Measurement m) {
       var location = repository
               .getLocationForDevice(m.device());
       var outcome = new Temperature(location, m.temp());
       return Record.of(location, outcome);
}

函数即服务和无服务器

由于其出色的启动时间和低内存使用量,您可以使用 Quarkus 在无服务器环境中实现函数。Quarkus 提供了 Funqy,这是一种编写函数的解决方案,该函数可以部署到各种 FaaS 环境中,例如 AWS Lambda、Azure Functions、Knative 和 Knative Events (Cloud Events)。它也可以用作独立服务。使用 Funqy,函数只是

import io.quarkus.funqy.Funq;

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

您可以在函数中使用任何 Quarkus 功能,并从快速启动和低内存利用率中受益。使用 Quarkus,您无需更改编程语言即可拥抱这个新世界。打包和部署轻而易举。Quarkus 会根据您定位的环境定制您的打包。

AI 注入应用程序

近年来,人工智能已从一项小众技术发展成为 IT 领域最具变革意义的创新之一。大型语言模型的兴起为构建更智能、更个性化和更具适应性的应用程序开辟了新的机遇。预测和生成式 AI 模型正越来越多地被集成,以提供更智能的用户体验、自动化决策制定并提高生产力。然而,开发 AI 注入应用程序并非没有挑战。这些模型通常是非确定性的,这意味着给定相同的输入,它们可能会产生不同的输出。它们还可能表现出幻觉行为,即模型生成不准确或荒谬的结果。此外,AI 系统容易受到有意或无意的滥用,从而导致侵犯隐私、安全风险或有偏差的结果。

为了解决这些复杂性,开发人员必须确保其 AI 驱动的应用程序既健壮又安全。这包括实施机制来处理不可预测的行为、验证和清理输入、监控输出是否存在潜在问题,以及审计 AI 交互以实现合规性和透明度。

Quarkus 为构建 AI 注入应用程序提供了一个无缝的解决方案。它自动管理与 AI 模型的通信,确保输入和输出得到充分保护和处理。Quarkus 还提供内置的审计和可观察性功能。

@RegisterAiService(retrievalAugmentor = MovieMuseRetrievalAugmentor.class)
@SessionScoped
public interface MovieMuse {

   @SystemMessage("""
           You are MovieMuse, an AI answering questions about
           the top 100 movies from IMDB.
           Your response must be polite, use the same language
           as the question, and be relevant to the question.
           Don't use any knowledge that is not in the
           database.
           """)
   String chat(@UserMessage String question);
}

通过利用 Quarkus,您可以专注于交付智能、前沿的应用程序,同时确保它们保持安全、可靠并符合行业标准。

连续性

Quarkus 的核心原则提供了一个通用的基础,使开发人员能够构建几乎任何类型的现代应用程序,从传统的单体应用到云原生、无服务器架构。它的灵活性使其成为各种规模和复杂性的应用程序的理想选择,使组织能够适应不断变化的业务需求和技术格局。Quarkus 的突出特点之一是其响应式核心。这使应用程序能够以卓越的效率处理当今最具挑战性的挑战。通过优化资源使用,Quarkus 确保应用程序可以无缝扩展,即使在高负载下也能最大限度地降低基础设施成本。该框架支持命令式和响应式编程模型,使开发人员可以根据项目的具体要求自由选择正确的方法。这种灵活性可以创建可以响应实时事件并轻松处理异步工作流程的高性能应用程序。

此外,Quarkus 在与其广泛的协议和通信风格进行交互的能力方面表现出色。无论您的应用程序是需要连接到遗留系统、微服务还是新兴的云技术,Quarkus 都可以促进顺畅的集成和交互,从而提高解决方案的整体适应性。它对事件驱动架构、RESTful API、gRPC 和其他现代协议的支持确保了由 Quarkus 驱动的应用程序能够很好地在分布式和动态环境中蓬勃发展。

总之,Quarkus 不仅是一个强大而高效的框架,而且是在当今快节奏的数字世界中构建多样化、可扩展和有弹性的应用程序的面向未来的解决方案。Quarkus 凭借其响应式核心、自适应开发模型和广泛的协议支持,提供了满足现代应用程序开发多样化和不断增长的需求的必要工具。