本文要点:
Helidon 是由 Oracle 在 2018 年 9 月份推出的轻量级微服务框架。
Helidon 是一个创建微服务应用的 Java 库的集合。
按照设计,Helidon 非常简单和快捷,它提供了两个版本:Helidon SE 和 Helidon MP。
Helidon 支持 GraalVM,能够将 Helidon SE 应用转换为原生可执行的代码。
在本教程中,我们将会向你介绍 Helidon,探索 Helidon SE 和 Helidon MP,并且会下载本教程相关的 GitHub 仓库内容。
Helidon 1.4.4 是当前的稳定版本,不过 Helidon 2.0 计划在今年发布。
2018 年 9 月份,Oracle 推出了新的开源框架Helidon项目。Helidon 最初的名字叫做 J4C(Java for Cloud),它是一个创建基于微服务应用的 Java 库的集合。在推出六个月之后,Helidon 1.0 于 2019 年 2 月份发布。目前的稳定发布版本是 Helidon 1.4.4,但是 Oracle 正在计划发布 Helidon 2.0(2.0 版本已经在 6 月 25 日发布,参见发布声明和变更记录——译者注)。
本教程将会介绍 Helidon SE 和 Helidon MP,探索 Helidon SE 的三个核心组件、如何起步并且还会介绍一个基于 Helidon MP 构建的电影应用。另外,我们还有关于 GraalVM 的讨论以及在即将发布的 Helidon 2.0 中都有哪些值得期待的功能。
Helidon 概览
按照设计,Helidon 非常简单和快捷,它很独特的一点在于它提供了两个编程模型 Helidon SE 和 Helidon MP。在下图中,展示与其他流行的微服务框架对比,Helidon SE 和 Helidon MP 分别位于什么地方。
Helidon SE
Helidon SE 是一个微框架,它提供了创建微服务的三个核心组件来构建基于微服务的应用,即 Web 服务器、配置以及安全性。它是一个很小的函数式 API,具有反应式(reactive)、简单和透明的特点,不需要应用服务器。
我们通过一个简单的例子看一下函数式风格的 Helidon SE,这里使用WebServer接口启动了一个 Helidon Web 服务器:
以该例子作为起点,我们将会增量式地构建一个正式的startServer()
方法,以此探索 Helidon SE 的三个核心组件,它是你所下载的服务器应用的一部分。
Web 服务器组件
受到 NodeJS 和其他 Java 框架灵感的启发,Helidon 的 web 服务器组件是一个运行在Netty上的异步反应式 API。WebServer
接口提供了基本的服务器生命周期和监控,可以通过配置、路由、错误处理以及构建度量指标和健康端点来进行增强。
我们从startServer()
方法的第一个版本开始,它会在一个随机可用的端口上启动 Helidon web 服务器:
首先,我们需要构建一个Routing接口的实例,它会作为一个具有路由规则的 HTTP 请求-响应处理器。在本例中,我们使用any()
方法将请求路由至定义好的服务器响应”Greetings from the web server!“,这个响应信息会通过浏览器或者curl
命令展示出来。
在构建 web 服务器的时候,我们调用了重载的create()
方法。按照设计,该方法用来接受各种服务器配置。如上所示,最简单的方式就是接受我们刚刚创建的用来提供默认服务器配置的实例变量routing
。
按照设计,Helidon Web 服务器是反应式的,这意味着start()
方法会返回一个CompletionStage<WebServer>接口的实例来启动 Web 服务器。它允许我们调用toCompletableFuture()
方法。因为这里没有指定服务器端口,服务器在启动的时候会选择任意一个可用的端口。
接下来,我们使用 Maven 构建并运行我们的服务器应用:
服务器启动的时候,我们会在终端窗口看到如下所示的输出:
如最后一行所示,Helidon web 服务器选择了 52535 端口。在服务器运行的时候,在浏览器输入这个 URL 或者在单独的终端窗口执行如下的curl
命令:
$ curl -X GET http://localhost:52535
我们将会看到“Greetings from the web server!”
要关闭 web 服务器,我们只需要添加如下这行代码:
配置组件
配置组件会加载和处理配置属性。Helidon 的Config接口将会从预先定义的配置文件中读取配置属性,配置文件通常是YAML格式,但是并不限于此。
我们创建一个application.yaml
文件,它提供了应用、服务器和安全性方面的配置。
application.yaml
文件中有三个主要的组成部分或者说是节点,即app
、server
和security
。前两个节点非常简单直接。greeting
子节点定义了我们在上述样例中硬编码的服务器响应。port
子节点定义了 web 服务器在启动的时候所使用的端点是 8080。但是,你应该也注意到了,security
节点要复杂一些,它使用 YAML 的映射序列定义了多个条目。通过使用“-
”字符分割,我们定义了两个安全 provider(即http-basic-auth
和http-digest-auth
)和两个用户(即ben
和mike
)。在本教程的安全组件章节,我们将会对其进行详细讨论。
另外,这个配置允许我们通过将config.require-encryption
设置为false
以使用明文密码。在生产环境中,我们显然需要将这个值设置为true
,这样的话试图传入明文密码会抛出异常。
现在,基于这个可用的配置文件,我们就可以更新startServer()
方法来使用刚刚定义的配置。
首先,我们需要通过调用Config
的create()方法构建该接口的一个实例。Config
提供的get(String key)
方法能够返回配置文件中给定key
所声明的节点或子节点。例如,config.get("server")将会返回server
节点下的内容,config.get("app.greeting")将会返回“Greetings from the web server!”。
接下来,我们创建了ServerConfiguration实例并为其提供不可变的 web 服务器信息,这是通过调用其create()
方法并传入 config.get("server")语句实现的。
实例变量routing
的构造方式和之前的样例很相似,只不过我们消除了硬编码的服务器响应,将其替换为调用 config.get("app.greeting").asString().get()。
Web 服务器的创建过程和之前的样例类似,只不过我们使用了一个不同版本的create()
方法,它接受两个实例变量serverConfig
和routing
。
我们可以使用相同的 Maven 和 Java 命令来构建和运行这个版本的 Web 服务器应用。执行相同的curl
命令:
$ curl -X GET http://localhost:8080
你应该会看到“Greetings from the web server!”
安全组件
Helidon 的安全组件提供了认证、授权、审计和出站安全性功能。在 Helidon 应用中,支持使用大量的安全供应商实现:
HTTP Basic 认证
HTTP Digest 认证
HTTP 签名
基于属性的访问控制(Attribute Based Access Control,ABAC)授权
JWT Provider
Header 断言
Google 登录认证
OpenID Connect
IDCS 角色映射(IDCS Role Mapping)
在 Helidon 应用中,我们可以采用如下三种方式的一种来实现安全性:
手动提供配置的构建者模式
提供配置文件的配置模式
组合使用构建者模式和配置模式的混合模式
在样例应用中,我们将会采用混合方式,但是我们首先要做一些准备工作。
我们看一下如何引用在配置文件中 security 节点下所定义的用户。考虑如下的字符串:
security.providers.0.http-basic-auth.users.0.login
当解析器遇到字符串中的数字时,就意味着配置文件中有一个或多个子节点。在本例中,providers
后面的0
将会指导解析器转移至第一个 provider 子节点,即http-basic-auth
。users
后面的0
将会指导解析器转移至包含login
、password
和roles
的第一个 user 子节点。因此,当传递到config.get()
方法时,上述的字符串将会返回ben
用户的 login、password 和 role 信息。与之类似,mike
用户的 login、password 和 role 信息可以通过如下的字符串获取到:
security.providers.0.http-basic-auth.users.1.login
接下来,我们为 Web 服务器应用创建一个新的类AppUser
,它实现了SecureUserStore.User接口:
我们将会使用这个类来构建角色和用户的 map,如下所示:
为了实现这一点,我们为 Web 服务器应用添加了一个新的方法getUsers()
,它会使用配置文件中http-basic-auth
子元素的配置来填充这个 map。
我们为 Web 服务器应用准备好了这个新功能,接下来,我们更新startServer()
方法,使用 Helidon 的 HTTP Basic 认证实现来为其添加安全性:
和前面样例做法一样,我们构建了变量实例config
和serverConfig
。随后,我们通过上述的getUsers()
方法构建了角色和用户的 map。
这里利用了Optional的空类型安全性,store
实例变量是通过SecureUserStore接口构建的,如 lambda 表达式所示。SecureUserStore 同时用于 HTTP Basic 认证和 HTTP Digest 认证。需要注意,HTTP Basic 可能是非安全的,即便使用 SSL 也是如此,因为密码并不是必需的。
我们现在已经准备好构建HTTPBasicAuthProvider实例了,它是SecurityProvider接口的一个实现类。realm()
方法定义了在未认证的时候发送至浏览器(或其他客户端)的安全 realm 名。因为我们在配置文件中定义了一个 realm,所以我们将它传递到了该方法中。subjectType()
方法定义了安全 provider 抽取或传播的 principal 类型。它会接受SubjectType枚举的两个值中的一个,也就是USER
或SERVICE
。userStore()
方法接受我们刚刚构建的store
实例变量,用来在我们的应用中校验用户。
借助provider
实例变量,我们现在就可以构建Security类的实例了,用来启动安全功能并将它与其他框架进行集成。我们使用config()
和addAuthenticationProvider()
来完成这一点。需要注意的是,我们可以注册多个安全 provider,只需要通过addAuthenticationProvider()
方法将它们链接在一起即可。例如,假设我们定义了实例变量basicProvider
和digestProvider
,它们分别代表HttpBasicAuthProvider
和HttpDigestAuthProvider类,那么我们的security
实例变量可以按照如下的方式进行构建:
WebSecurity类实现了Service接口,它封装了一组路由规则和相关逻辑。实例变量webSecurity
是通过create()
方法和securityDefaults()
方法构建的,前者将security
实例变量传递了进去而后者则将WebSecurity.authentic()
传递了进去,从而确保请求将会经过认证过程。
我们熟悉的实例变量routing
并没有太大的差异,在前面两个样例中我们已经构建过它。它注册了webSecurity
实例变量并定义了端点“/
”、“/admin
”和“/user
”,这是通过get()
方法将它们链接起来的。注意,/admin
和/user
端点分别关联了ben
和mike
。
最后,我们的 web 服务器就可以启动了!在实现了所有的零部件之后,构建 web 服务器就和之前的样例完全一样了。
现在,我们可以使用相同的 Maven 和 Java 命令构建和运行 web 服务器应用了,执行如下的curl
命令:
$ curl -X GET [http://localhost:8080/](http://localhost:8080/)
将会返回“Greetings from the web server!”
$ curl -X GET [http://localhost:8080/admin](http://localhost:8080/admin)
将会返回“Greetings from the admin, ben!”
$ curl -X GET [http://localhost:8080/user](http://localhost:8080/user)
将会返回“Greetings from the user, mike!”
你可以看到阐述所有三个版本startServer()
方法的综合服务器应用,它们关联了我们刚刚探讨的三个 Helidon SE 核心组件。同时,你也可以参考更广泛的安全样例,它们会为你展示如何实现其他的安全 provider。
Helidon MP
Helidon MP 构建在 Helidon SE 之上,是一个小型的、声明式风格的 API,它是MicroProfile规范的实现,MicroProfile是一个平台,致力于将企业级 Java 优化为微服务架构,适用于构建基于微服务的应用。MicroProfile 最初是由 IBM、Red Hat、Payara 和 Tomitribe 在 2006 年联合成立的,当时它定义了最初的三个 API,即 CDI (JSR 365)、JSON-P (JSR 374)和 JAX-RS (JSR-370),它们被认为是构建微服务应用所需的最小数量的 API。从那时开始,MicroProfile 已经发展到 12 个核心 API 以及支持反应式流和 GraphQL 的 4 个独立 API。MicroProfile 3.3 于 2020 年 2 月发布,是最新的版本。
Helidon MP 目前支持 MicroProfile 3.2。对于 Java EE/Jakarta EE 开发人员来说,Helidon MP 是一个非常好的可选方案,因为它使用注解实现了熟悉的声明式方式。它不需要特殊的部署模型,也不需要额外的 Java EE 打包。
我们看一下 Helidon MP 的声明式风格,这是一个启动 Helidon web 的简单样例,可以将其与 Helidon SE 的函数式风格进行一下对比。
请注意这种风格与 Helidon SE 函数式风格的差异。
Helidon 架构
既然已经介绍了 Helidon SE 和 Helidon MP,那么我们看一下它们是如何组合在一起的。Helidon 的架构如下图所示。Helidon MP 是构建在 Helidon SE 和 CDI 扩展之上的,如下文所述,CDI 扩展丰富了 Helidon MP 的云原生能力。
CDI Extensions
Helidon 提供了可迁移的上下文与依赖注入(Context and Dependency Injection,CDI)扩展,它支持与各种数据源、事务和客户端进行集成,扩展 Helidon MP 应用的云原生功能。目前它提供了如下的扩展:
HikariCP,”零开销“生产环境就绪的 JDBC 连接池数据源
Oracle Universal Connection Datapool (UCP)数据源
Oracle Cloud Infrastructure (OCI) 对象存储客户端
Java Transactional API (JTA) 事务
Helidon 快速上手指南
Helidon 为Helidon SE和Helidon MP都提供了快速上手指南。我们只需要访问这些页面并遵循指令即可。例如,我们可以通过在终端窗口执行如下的 Maven 命令就能快速构建一个 Helidon SE 应用:
这将会在helidon-quickstart-se
目录下生成一个小型的但是可运行的应用,它包含了测试和各种配置文件,这些配置文件用于应用(application.yaml
)、日志(logging.properties
)、使用 GraalVM 构建原生镜像(native-image.properties
)、使用 Docker 容器化应用(Dockerfile
和Dockerfile.native
)以及使用 Kubernetes 进行应用编排(app.yaml
)。
类似地,我们可以快速构建 Helidon MP 应用:
对于构建复杂的应用来讲,这是一个很好的起点,我们会在下一节讨论一个复杂的应用。
Movie 应用
基于所生成的 Helidon MP 快速上手应用,我们添加了一些额外的类完成了movie应用,新增加的类包括 POJO、资源、repository、自定义异常以及ExceptionMapper的实现,该应用会维护 Quentin Tarantino 电影的一个列表。HelidonApplication
类如下所示,它会注册所需的类。
你可以 colne GitHub 仓库以了解关于该应用的详细信息。
GraalVM
Helidon 支持GraalVM,它是一个多语言的虚拟机和平台,能够将应用转换成原生可执行代码。GraalVM 是由Oracle Labs创建的,由Graal、SubstrateVM和Truffle组成,其中 Graal 是一个使用 Java 编写的即时编译器,SubstrateVM 是一个允许提前将 Java 应用编译为可执行镜像的框架,Truffle 则是一个用于构建语言解释器(interpreter)的开源工具集和 API。它最新的版本是 20.1.0。
我们可以通过 GraalVM 的native-image
工具将 Helidon SE 应用转换成原生可执行代码,native-image
需要通过 GraalVM 的gu
工具单独进行安装:
安装完成之后,我们就可以回到helidon-quickstart-se
目录并执行如下的命令:
$ mvn package -Pnative-image
这个操作将会耗时几分钟,完成之后,我们的应用就转换成了原生代码。可执行文件位于/target
目录下。
Helidon 2.0 的路线图
Helidon 2.0.0 计划在 2020 年发布(目前,该版本已经发布,读者可以参考该地址——译者注)。该版本重要的新特性包括为 Helidon MP 应用添加对 GraalVM 的支持、新的 Web Client 和DB Client组件、新的CLI工具以及独立 MicroProfile Reactive Messaging和Reactive Streams Operators API 的实现。
直到最近,由于用到了 CDI 2.0(JSR 365)的反射(这是 MicroProfile API 的一个核心 API),所以只有 Helidon SE 应用能够利用 GraalVM。但是,根据客户的需要,Helidon 2.0.0 将支持 Helidon MP 应用转换成原生镜像。Oracle 创建了一个示例应用为 Java 社区预览这个新特性。
为了补充原有的三个核心 Helidon SE API,即 Web 服务器、配置和安全性,新的Web Client API 完备了 Helidon SE 的特性集。通过构建WebClient接口的实例,我们能够处理对特定端点的 HTTP 请求和响应。和 Web Server API 一样,Web Client 也可以通过配置文件进行配置。
我们可以详细了解开发人员可以期待 Helidon 2.0.0 会带来哪些新功能。
作者简介:
Michael Redlich 是新泽西州克林顿市ExxonMobil研究与工程部门的高级研究技术人员(观点仅代表个人),在过去的 30 年里,他具有开发定制科学实验室和 web 应用的经验。他还曾经在 Ai-Logix, Inc.(现在是AudioCodes了)担任过技术支持工程师,为客户提供技术支持和开发电话应用程序。他的技术专长包括面向对象设计和分析、关系型数据库设计和开发、计算机安全、C/ C++、Java、Python 和其他编程/脚本语言。他最近的关注点包括MicroProfile、Jakarta EE、Helidon、Micronaut和MongoDB。
原文链接:
Project Helidon Tutorial: Building Microservices with Oracle’s Lightweight Java Framework
评论