用Helidon构建REST APIs和本地Java应用程序教程

338 阅读5分钟

Helidon项目是一套用于编写微服务的Java库。它是一个开源的、Apache 2.0许可的、由Oracle赞助的项目,包含对MicroProfile的支持,以及一个反应式的、功能性的API。Helidon的两种不同风格分别被称为Helidon MP和SE。helidon.io网站说。

由于Helidon只是一个运行在快速Netty核心上的Java库集合,所以没有额外的开销或臃肿。

今天,我将对这一说法进行测试首先,我将告诉你如何运行一个安全的、受OAuth 2.0保护的、允许JWT认证的Java REST API。然后,我将向你展示如何用GraalVM构建一个本地镜像。最后,我将把Helidon与最流行的Java REST API框架进行比较。Micronaut、Quarkus和Spring Boot。

我在《用Micronaut、Quarkus和Spring Boot构建本地Java应用》一文中比较了这三个框架的启动时间和内存使用情况。Helidon的表现如何?请继续阅读!

开始使用Helidon

我创建了一个GitHub仓库,你可以克隆并运行,以快速开始使用Helidon。

git clone https://github.com/oktadev/native-java-examples.git
cd native-java-examples/helidon

在下面一节中,我将向你展示我是如何创建这个例子的。首先,让我们看看如何运行它。

在你喜欢的IDE中打开helidon 目录,这样你就可以很容易地访问这个例子的项目文件。

如果你只想看看如何构建一个本地镜像,请跳到构建一个本地Helidon应用部分。

用GraalVM安装JDK

你需要一个带有GralVM的JDK和它的native-image 编译器。使用SDKMAN,运行以下命令并将其设置为默认值:

sdk install java 21.3.0.r17-grl

将本地扩展添加到JDK中:

gu install native-image

运行一个Helidon Java API

在一个终端窗口中,运行mvn package ,将应用程序打包成JAR。然后使用java -jar 来运行它:

mvn package
java -jar target/helidon.jar
Helidon的Maven插件没有运行命令。你可以安装Helidon CLI并运行helidon dev 。运行这个命令可以修改代码,并自动重新编译和重启你的应用程序。

如果你打开另一个终端窗口并试图用HTTPie访问它,你会得到一个401未经授权的错误。

$ http :8080/hello

HTTP/1.1 401 Unauthorized
Content-Length: 0
Date: Tue, 4 Jan 2022 10:17:11 -0700
connection: keep-alive

为了使你能访问这个端点,你需要生成一个OAuth 2.0访问令牌,并将JWKS(JSON Web Key Sets)的URL更新为你的(在这个项目的application.yml )。

如果你不确定什么是OIDC和OAuth 2.0,请参阅什么是OAuth?

在你开始之前,你需要一个免费的Okta开发者账户。安装Okta CLI,运行okta register ,注册一个新的账户。如果你已经有一个账户,运行okta login 。然后,运行okta apps create 。选择默认的应用程序名称,或根据你的需要进行更改。 选择单页应用程序,然后按回车键

在重定向URI中使用https://oidcdebugger.com/debug ,并将注销重定向URI设置为https://oidcdebugger.com

Okta CLI是做什么的?

Okta CLI将在您的Okta组织中创建一个OIDC单页应用。它将添加您指定的重定向URI,并授予Everyone组的访问权。它还会为https://oidcdebugger.com 添加一个受信任的来源。当它完成时,你会看到如下的输出。

Okta application configuration:
Issuer:    https://dev-133337.okta.com/oauth2/default
Client ID: 0oab8eb55Kb9jdMIr5d6

注意:您也可以使用Okta管理控制台来创建您的应用程序。更多信息请参见创建一个单页应用程序

请注意clientIdissuer 的值。你将需要这些来获得访问令牌,并为JWT认证配置每个框架。

打开src/main/resources/META-INF/microprofile-config.properties ,修改Okta的URL,使之与你的相匹配。

mp.jwt.verify.issuer=/oauth2/default
mp.jwt.verify.publickey.location=${mp.jwt.verify.issuer}/v1/keys

用Ctrl+C停止你的Helidon应用,重新打包,然后用⬆️+Return重新运行它。

mvn package
java -jar target/helidon.jar

生成一个OAuth 2.0访问令牌

获得访问令牌的一个简单方法是使用OpenID Connect Debugger生成一个访问令牌。首先,你必须在Okta上配置你的应用程序,以使用OpenID Connect的隐式流程。

运行okta login ,在浏览器中打开生成的URL。转到应用程序部分,选择您刚刚创建的应用程序。编辑它的常规设置,添加隐式(混合)作为允许的授予类型,并启用访问令牌。然后,确保它的登录重定向URI中有https://oidcdebugger.com/debug 。点击 "保存"并复制客户端ID,以便进行下一步操作。

现在,导航到OpenID Connect调试器网站。填入你的客户ID,并在授权URI中使用/oauth2/default/v1/authorizestate 字段必须填写,但可以包含任何字符。为响应类型选择token

OIDC Debugger

点击发送请求,继续。

一旦你有了访问令牌,在终端窗口将其设置为TOKEN 环境变量。

TOKEN=eyJraWQiOiJZMVRxUkRQbEFEcm1XN0dX...

用HTTPie测试你的Helidon API

使用HTTPie将JWT作为承载令牌传入Authorization header中。

http :8080/hello Authorization:"Bearer $TOKEN"

你应该得到一个包含你的电子邮件地址的200响应。

HTTPie call to Helidon’s /hello with bearer token

构建一个本地Helidon应用程序

要将这个Helidon应用程序编译成一个本地二进制文件,请运行:

mvn package -Pnative-image

这个命令将需要几分钟的时间来完成。我的2019年MacBook Pro配备了2.4GHz的8核英特尔酷睿i9处理器和64GB的内存,需要2分钟14秒才能完成。

./target/helidon 启动它。

$ ./target/helidon
...

2022.01.04 10:28:37 INFO io.helidon.microprofile.server.ServerCdiExtension Thread[main,5,main]: Registering JAX-RS Application: HelloApplication
2022.01.04 10:28:37 WARNING org.glassfish.jersey.internal.Errors Thread[main,5,main]: The following warnings have been detected: WARNING: The (sub)resource method hello in com.okta.rest.controller.HelloResource contains empty path annotation.

2022.01.04 10:28:37 INFO io.helidon.webserver.NettyWebServer Thread[nioEventLoopGroup-2-1,10,main]: Channel '@default' started: [id: 0xbecd2683, L:/[0:0:0:0:0:0:0:0]:8080]
2022.01.04 10:28:37 INFO io.helidon.microprofile.server.ServerCdiExtension Thread[main,5,main]: Server started on http://localhost:8080 (and all other host addresses) in 53 milliseconds (since JVM startup).
2022.01.04 10:28:37 INFO io.helidon.common.HelidonFeatures Thread[features-thread,5,main]: Helidon MP 2.4.1 features: [CDI, Config, Fault Tolerance, Health, JAX-RS, Metrics, Open API, REST Client, Security, Server, Tracing, Web Client]
2022.01.04 10:28:37 INFO io.helidon.common.HelidonFeatures.experimental Thread[features-thread,5,main]: You are using experimental features. These APIs may change, please follow changelog!
2022.01.04 10:28:37 INFO io.helidon.common.HelidonFeatures.experimental Thread[features-thread,5,main]: 	Experimental feature: Web Client (WebClient)

正如你所看到的,它只用了50多毫秒就启动了!用HTTPie和一个访问令牌来测试它。如果你的JWT已经过期,你可能需要用oidcdebugger.com生成一个新的JWT。

http :8080/hello Authorization:"Bearer $TOKEN"

从头开始创建一个Helidon应用程序

你可能会想,"你是如何建立一个安全的Helidon应用的"?我只是隐藏了复杂性吗?不,只需要五个步骤就可以创建同样的应用程序:

  1. 安装Helidon的CLI并运行helidon init ,或者使用Maven。

    mvn -U archetype:generate -DinteractiveMode=false \
     -DarchetypeGroupId=io.helidon.archetypes \
     -DarchetypeArtifactId=helidon-quickstart-mp \
     -DarchetypeVersion=2.4.1 \
     -DgroupId=com.okta.rest \
     -DartifactId=helidon \
     -Dpackage=com.okta.rest
    

    如果你使用helidon init ,像我一样回答问题。

    helidon init command

  2. src/main/java/com/okta/rest/controller/HelloResource.java 中添加一个HelloResource

    package com.okta.rest.controller;
    
    import io.helidon.security.Principal;
    import io.helidon.security.SecurityContext;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.Context;
    import java.util.Optional;
    
    import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
    
    @Path("/hello")
    public class HelloResource {
    
        @GET
        @Path("/")
        @Produces(TEXT_PLAIN)
        public String hello(@Context SecurityContext context) {
            Optional<Principal> userPrincipal = context.userPrincipal();
            return "Hello, " + userPrincipal.get().getName() + "!";
        }
    }
    
  3. src/main/resources/META-INF/microprofile-config.properties 中启用并配置JWT安全。

    mp.jwt.verify.issuer=/oauth2/default
    mp.jwt.verify.publickey.location=${mp.jwt.verify.issuer}/v1/keys
    
  4. src/main/java/com/okta/rest 中添加一个HelloApplication 类来注册你的资源并配置JWT认证。

    package com.okta.rest;
    
    import com.okta.rest.controller.HelloResource;
    import org.eclipse.microprofile.auth.LoginConfig;
    
    import javax.enterprise.context.ApplicationScoped;
    import javax.ws.rs.core.Application;
    import java.util.Set;
    
    @LoginConfig(authMethod = "MP-JWT")
    @ApplicationScoped
    public class HelloApplication extends Application {
    
        @Override
        public Set<Class<?>> getClasses() {
            return Set.of(HelloResource.class);
        }
    }
    
  5. 删除GreetingsProvider,GreetResource, 和MainTest ,因为它们在这个例子中没有被使用。

    rm src/main/java/com/okta/rest/Greet*
    rm src/test/java/com/okta/rest/MainTest.java
    

这就是了!现在你可以启动应用程序或建立如上所示的本地图像。

本地Java启动时间比较

为了比较Micronaut、Quarkus、Spring Boot和Helidon的启动时间,我首先创建了本地可执行文件。你可以在你克隆的例子的根目录下运行下面的命令来做同样的事情。

cd micronaut
./mvnw package -Dpackaging=native-image

cd ../quarkus
./mvnw package -Pnative

cd ../spring-boot
./mvnw package -Pnative

# Helidon should already be built, but just in case it isn't
cd ../helidon
mvn package -Pnative-image

在我开始记录数字之前,我对每个图像都运行了三次。然后我将每个命令运行了五次。

这些数字来自2019年的MacBook Pro,配备2.4GHz 8核英特尔酷睿i9处理器和64GB内存。我认为有必要注意的是,我的WiFi连接是9.88Mbps向下,0.37Mbps向上(根据Speedtest应用程序)。

我还使用下面的命令测试了每个应用程序的内存使用量(MB)。在测量之前,我确保向每个应用程序发送一个HTTP请求。

ps -o pid,rss,command | grep --color <executable> | awk '{$2=int($2/1024)"M";}{ print;}'