在本教程中,我将向你展示如何用Helidon创建一个安全的REST API和本地图像。你将看到如何运行一个安全的、受OAuth 2.0保护的、允许JWT认证的Java REST API。然后,我将比较它与Micronaut、Quarkus和Spring Boot的性能。
本教程也可作为截屏提供。
先决条件。
| 一些步骤后面的括号表示我在视频中使用的IntelliJ Live模板。你可以在mraible/idea-live-templates找到模板的定义。 |
目录
- 用GraalVM安装JDK
- 生成一个OAuth 2.0访问令牌
- 用Helidon构建Java REST API
- 启动时间比较
- 内存使用比较
- 原生Java REST API框架的比较 现场直播
- 用Helidon确保本地Java的安全FTW!
用GraalVM安装JDK
使用SDKMAN用GraalVM安装Java 17
sdk install java 22.1.0.r17-grl
生成一个OAuth 2.0访问令牌
-
安装Okta CLI并运行
okta register,以注册一个新账户。如果你已经有一个账户,运行okta login。 -
运行
okta apps create spa。设置oidcdebugger作为应用程序名称,然后按回车键。 -
在重定向URI中使用
https://oidcdebugger.com/debug,并将注销重定向URI设置为https://oidcdebugger.com。 -
-
填入你的客户ID
-
在授权URI中使用
/oauth2/default/v1/authorize -
为响应类型选择代码并使用PKCE
-
点击发送请求,继续
-
-
在终端窗口中将访问令牌设置为
TOKEN环境变量。TOKEN=eyJraWQiOiJYa2pXdjMzTDRBYU1ZSzNGM...
用Helidon建立一个Java REST API
-
创建一个支持OAuth 2.0的Helidon应用。
mvn -U archetype:generate -DinteractiveMode=false \ -DarchetypeGroupId=io.helidon.archetypes \ -DarchetypeArtifactId=helidon-quickstart-mp \ -DarchetypeVersion=2.5.0 \ -DgroupId=com.okta.rest \ -DartifactId=helidon \ -Dpackage=com.okta.rest你也可以安装Helidon的CLI并运行 helidon init。 -
在
pom.xml中添加MicroProfile JWT支持。<dependency> <groupId>io.helidon.microprofile.jwt</groupId> <artifactId>helidon-microprofile-jwt-auth</artifactId> </dependency> -
添加一个
HelloResource类,返回用户的信息。[h-hello]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 @Produces(TEXT_PLAIN) public String hello(@Context SecurityContext context) { Optional<Principal> userPrincipal = context.userPrincipal(); return "Hello, " + userPrincipal.get().getName() + "!"; } } -
在
src/main/java/com/okta/rest中添加一个HelloApplication类来注册你的资源并配置JWT认证。[h-app]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); } } -
添加你的Okta端点到
src/main/resources/META-INF/microprofile-config.properties。mp.jwt.verify.publickey.location=/oauth2/default/v1/keys mp.jwt.verify.issuer=/oauth2/default
使用HTTPie运行和测试你的Helidon REST API
-
从你的IDE或使用终端启动你的应用程序。
mvn package && java -jar ./target/helidon.jar -
用访问令牌测试你的API。
http :8080/hello Authorization:"Bearer $TOKEN"
用GraalVM构建一个本地Helidon应用程序
-
使用
native-imageprofile将你的Helidon应用编译成一个本地可执行文件。mvn package -Pnative-image -
启动你的Helidon应用。
./target/helidon -
使用访问令牌测试你的API。
http :8080/hello Authorization:"Bearer $TOKEN"
启动时间比较
在记录数字之前,我通过运行每个图像三次来比较各框架的启动时间。然后,我又将每个应用程序运行了五次,并对结果进行了平均。我在一台2019年的MacBook Pro上收集了这些数字,它带有固态硬盘、2.4 GHz的8核英特尔酷睿i9处理器和64GB的内存。
google.charts.load('current', {packages: ['corechart', 'bar']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ [ 'Framework', 'Milliseconds to start', { role: 'style' }], [ 'Quarkus', 19.2, 'red'], ['Micronaut', 27.8, 'blue'], ['Helidon', 42.4, 'orange'], ['Spring Boot', 58.6, 'green'] ]; var options = { title: '本地Java框架的启动时间', chartArea:{width: '50%'}, hAxis: { title: 'Milliseconds', minValue: 0 }, vAxis: { title: 'Java Framework' } }; var chart = new google.visualization.BarChart(document.getElementById('startup-times') ); chart.draw(data, options); }
使用的版本。Quarkus 2.9.0,Micronaut 3.4.3,Helidon 2.5.0,以及Spring Boot 2.6.7与Spring Native 0.11.5。
内存使用情况比较
我使用下面的命令测试了每个应用程序的内存使用情况(以兆字节为单位)。我在启动应用程序后立即运行了它,在一个认证请求后,以及在五个认证请求后。
ps -o pid,rss,command | grep --color <executable> | awk '{$2=int($2/1024)"M";}{ print;}'
下面的图表显示了五个请求后的内存使用情况。
google.charts.load('current', {packages: ['corechart', 'bar']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Framework', 'Memory usage (MB)', { role: 'style' }], ['Quarkus', 36, 'red'], ['Micronaut', 56, 'blue'], ['Spring Boot', 62, 'green'], ['Helidon', 62, 'orange'], ] ) ; var options = { title: '本地Java框架的内存使用', chartArea:{width: '50%'}, hAxis: { title: 'Megabytes', minValue: 0 }, vAxis: { title: 'Java Framework' } }; var chart = new google.visualization.BarChart(document.getElementById('memory-usage') ) ; chart.draw(data, options); }
MacBook Pro M1 Max的情况如何?
我的MacBook Pro(16英寸,2021年)采用苹果M1 Max,构建速度快得多,应用程序启动速度快2倍,但它们使用的内存更多。
google.charts.load('current', {packages: ['corechart', 'bar']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Framework', 'Milliseconds to start', { role: 'style' }], ['Quarkus', 12, 'red'], ['Micronaut', 17, 'blue'], ['Helidon', 23, 'orange'], ['Spring Boot', 36, 'green'] ] ) ; var options = { title: '苹果硅上Java REST框架的启动时间' , chartArea:{width: '50%'}, hAxis: { title: 'Milliseconds', minValue: 0 }, vAxis: { title: 'Java Framework' } }; var chart = new google.visualization.BarChart(document.getElementById('startup-times-m1')); chart.raw(data, options); }
google.charts.load('current', {packages: ['corechart', 'bar']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Framework', 'Memory usage (MB)', { role: 'style' }], ['Quarkus', 47, 'red'], ['Micronaut', 68, 'blue'], ['Spring Boot', 75, 'green'], ['Helidon', 84, 'orange'], ] ; var options = { title: '苹果硅上Java REST框架的内存使用', chartArea:{width: '50%'}, hAxis: { title: 'Megabytes', minValue: 0 }, vAxis: { title: 'Java Framework' } }; var chart = new google.visualization.BarChart(document.getElementById('memory-use-m1')); chart.raw(data, options); }