helidon使用_Helidon项目教程:使用Oracle轻量级Java框架构建微服务

helidon使用

重要要点

  • 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计划于2020年Spring末发布。

Oracle在2018年9月推出了新的开源框架Project Helidon 。最初名为J4C(Java for Cloud),Helidon是用于创建基于微服务的应用程序的Java库的集合。 在引入Helidon 1.0的六个月内,它于2019年2月发布。当前的稳定版本是Helidon 1.4.4,但是Oracle计划在2020年Spring末发布Helidon 2.0的过程中进展良好。

本教程将介绍Helidon SE和Helidon MP,探索Helidon SE的三个核心组件,如何入门,并介绍在Helidon MP之上构建的电影应用程序。 还将讨论GraalVM,以及即将发布的Helidon 2.0会带来什么。

直升机场景观

Helidon设计简单,快速,是独一无二的,因为它附带两种编程模型: Helidon SEHelidon MP 。 在下图中,您可以看到Helidon SE和Helidon MP与其他流行的微服务框架保持一致的地方。

Helidon SE

Helidon SE是一个微框架,具有创建微服务所需的三个核心组件-Web服务器,配置和安全性-用于构建基于微服务的应用程序。 它是一种小型的,功能性的API,具有React性,简单和透明的特点,不需要应用程序服务器。

让我们看一下有关使用WebServer界面启动Helidon Web服务器的非常简单的示例的Helidon SE的功能样式:

WebServer.create(
    Routing.builder()
        .get("/greet", (req, res)
             -> res.send("Hello World!"))
        .build())
    .start();

以该示例为起点,我们将逐步构建一个正式的startServer()方法(该服务器应用程序的一部分供您下载),以探索三个Helidon SE核心组件。

Web服务器组件

受NodeJS和其他Java框架的启发,Helidon的Web服务器组件是运行在Netty之上的异步和响应式API。 WebServer界面通过配置,路由,错误处理以及构建指标和运行状况端点来增强基本的服务器生命周期和监视。

让我们从startServer()方法的第一个版本开始,在随机可用端口上启动Helidon Web服务器:

private static void startServer() {
    Routing routing = Routing.builder()
            .any((request, response) -> response.send("Greetings from the web server!" + "\n"))
            .build();

    WebServer webServer = WebServer
            .create(routing)
            .start()
            .toCompletableFuture()
            .get(10, TimeUnit.SECONDS);

    System.out.println("INFO: Server started at: http://localhost:" + webServer.port() + "\n");
    }

首先,我们需要构建一个Routing接口的实例,该实例用作带有路由规则的HTTP请求-响应处理程序。 在此示例中,我们使用any()方法将请求路由到定义的服务器响应“来自Web服务器的问候!”,该响应将显示在浏览器中或通过curl命令显示。

在构建Web服务器时,我们调用旨在接受各种服务器配置的重载create()方法。 如上所示,最简单的方法接受我们刚刚创建的实例变量routing ,以提供默认服务器配置。

Helidon Web服务器被设计为可响应的,这意味着start()方法将返回,并且CompletionStage<WebServer>接口的实例将启动该Web服务器。 这使我们可以调用toCompletableFuture()方法。 由于未定义特定的服务器端口,因此服务器将在启动时找到随机可用的端口。

让我们使用Maven构建并运行我们的服务器应用程序:

$ mvn clean package
$ java -jar target/helidon-server.jar

服务器启动时,您应该在终端窗口中看到以下内容:

Apr 15, 2020 1:14:46 PM io.helidon.webserver.NettyWebServer <init>
INFO: Version: 1.4.4
Apr 15, 2020 1:14:46 PM io.helidon.webserver.NettyWebServer lambda$start$8
INFO: Channel '@default' started: [id: 0xcba440a6, L:/0:0:0:0:0:0:0:0:52535]
INFO: Server started at: http://localhost:52535

如最后一行所示,Helidon Web服务器选择了端口52535。服务器运行时,请在浏览器中输入此URL,或在单独的终端窗口中使用以下curl命令执行该URL:

$ curl -X GET http://localhost:52535

您应该看到“ 来自Web服务器的问候!

要关闭Web服务器,只需添加以下代码行:

webServer.shutdown()
        .thenRun(() -> System.out.println("INFO: Server is shutting down...Good bye!"))
        .toCompletableFuture();

配置组件

配置组件加载并处理配置属性。 Helidon的Config界面将从定义的属性文件中读取配置属性,通常但不限于以YAML格式。

让我们创建一个application.yaml文件,它将为应用程序,服务器和安全性提供配置。

app:
  greeting: "Greetings from the web server!"

server:
  port: 8080
  host: 0.0.0.0

security:
  config:
    require-encryption: false

  providers:
    - http-basic-auth:
        realm: "helidon"
        users:
          - login: "ben"
            password: "${CLEAR=password}"
            roles: ["user", "admin"]
          - login: "mike"
            password: "${CLEAR=password}"
            roles: ["user"]
    - http-digest-auth:

application.yaml文件appserversecurity有三个主要部分或节点。 前两个节点很简单。 greeting子节点定义了我们在上一个示例中进行硬编码的服务器响应。 port子节点定义了Web服务器在启动时使用的端口8080。 但是,您应该已经注意到,利用YAML的映射序列来定义多个条目, security节点要复杂一些。 用' - '字符分隔,定义了两个安全提供程序http-basic-authhttp-digest-auth ,以及两个用户benmike 。 我们将在本教程的“ 安全性组件”部分中对此进行更详细的讨论。

还要注意,此配置允许使用明文密码,因为config.require-encryption子节设置为false 。 您显然会在生产环境中将此值设置为true ,以便任何尝试传递明文密码的尝试都将引发异常。

现在我们有了一个可行的配置文件,让我们更新startServer()方法以利用我们刚刚定义的配置。

private static void startServer() {
    Config config = Config.create();
    ServerConfiguration serverConfig = ServerConfiguration.create(config.get("server"));

    Routing routing = Routing.builder()
            .any((request, response) -> response.send(config.get("app.greeting").asString().get() + "\n"))
            .build();

    WebServer webServer = WebServer
            .create(serverConfig, routing)
            .start()
            .toCompletableFuture()
            .get(10, TimeUnit.SECONDS);

    System.out.println("INFO: Server started at: http://localhost:" + webServer.port() + "\n");
    }

首先,我们需要通过调用Config接口的create()方法来构建Config接口的实例,以读取我们的配置文件。 Config提供的get(String key)方法从key指定的配置文件中返回一个节点或特定的子节点。 例如, config.get("server")将返回server节点下的内容,而config.get("app.greeting")将返回“ 来自Web服务器的问候! ”。

接下来,我们通过传入语句config.get("server")来调用ServerConfigurationcreate()方法,从而创建ServerConfiguration实例,以提供不可变的Web服务器信息。

除了我们通过调用config.get("app.greeting").asString().get()消除了对服务器响应的硬编码之外,实例变量routing的构建与上一个示例相同。

除了我们使用不同版本的create()方法来接受两个实例变量serverConfigrouting之外,该Web服务器的创建与前面的示例相同。

现在,我们可以使用相同的Maven和Java命令来构建和运行此版本的Web服务器应用程序。 执行相同的curl命令:

$ curl -X GET http://localhost:8080

您应该看到“ 来自Web服务器的问候!

安全组件

Helidon的安全组件提供身份验证,授权,审核和出站安全。 有许多已实现的安全提供程序支持在Helidon应用程序中使用:

  • HTTP基本认证
  • HTTP摘要验证
  • HTTP签名
  • 基于属性的访问控制(ABAC)授权
  • JWT提供商
  • 标头声明
  • Google登录身份验证
  • OpenID连接
  • IDCS角色映射

您可以使用以下三种方法之一在Helidon应用程序中实现安全性:

  • 您手动提供配置的构建器模式
  • 通过配置文件提供配置的配置模式
  • 构建器和配置模式的混合体

我们将使用混合方法在应用程序中实现安全性,但是我们需要先做一些内部管理。

让我们回顾一下如何引用在配置文件的安全性节点下定义的用户。 考虑以下字符串:

security.providers.0.http-basic-auth.users.0.login

当解析器遇到字符串中的数字时,表明配置文件中存在一个或多个子节点。 在此示例中, providers之后的0将指示解析器移动到第一个提供者子节点http-basic-auth 。 在0之后users直接将解析器移动到包含第一子节点的用户loginpasswordroles 。 因此,当传递给config.get()方法时,上述字符串将返回用户ben的登录名,密码和角色信息。 同样,将使用以下字符串返回用户mike的登录名,密码和角色信息:

security.providers.0.http-basic-auth.users.1.login

接下来,让我们为Web服务器应用程序AppUser创建一个新类, AppUser实现SecureUserStore.User接口:

public class AppUser implements SecureUserStore.User {

    private String login;
    private char[] password;
    private Collection<String> roles;

    public AppUser(String login, char[] password, Collection<String> roles) {
        this.login = login;
        this.password = password;
        this.roles = roles;
        }
    
    @Override
    public String login() {
        return login;
        }

    @Override
    public boolean isPasswordValid(char[] chars) {
        return false;
        }

    @Override
    public Collection<String> roles() {
        return roles;
        }

    @Override
    public Optional<String> digestHa1(String realm, HttpDigest.Algorithm algorithm) {
        return Optional.empty();
        }
    }

我们将使用此类来构建用户角色映射,即:

Map<String, AppUser> users = new HashMap<>();

为此,我们向Web服务器应用程序添加了一个新方法getUsers() ,该方法使用来自配置文件的http-basic-auth子节中的配置来填充地图。

private static Map<String, AppUser> getUsers(Config config) {
    Map<String, AppUser> users = new HashMap<>();

    ConfigValue<String> ben = config.get("security.providers.0.http-basic-auth.users.0.login").asString();
    ConfigValue<String> benPassword = config.get("security.providers.0.http-basic-auth.users.0.password").asString();
    ConfigValue<List<Config>> benRoles = config.get("security.providers.0.http-basic-auth.users.0.roles").asNodeList();

    ConfigValue<String> mike = config.get("security.providers.0.http-basic-auth.users.1.login").asString();
    ConfigValue<String> mikePassword = config.get("security.providers.0.http-basic-auth.users.1.password").asString();
    ConfigValue<List<Config>> mikeRoles = config.get("security.providers.0.http-basic-auth.users.1.roles").asNodeList();

    users.put("admin", new AppUser(ben.get(), benPassword.get().toCharArray(), Arrays.asList("user", "admin")));
    users.put("user", new AppUser(mike.get(), mikePassword.get().toCharArray(), Arrays.asList("user")));

    return users;
    }

现在,我们已经在Web服务器应用程序中内置了此新功能,让我们更新startServer()方法,以通过Helidon的HTTP基本身份验证实现增加安全性:

private static void startServer() {
    Config config = Config.create();
    ServerConfiguration serverConfig = ServerConfiguration.create(config.get("server"));

    Map<String, AppUser> users = getUsers(config);
    displayAuthorizedUsers(users);

    SecureUserStore store = user -> Optional.ofNullable(users.get(user));

    HttpBasicAuthProvider provider = HttpBasicAuthProvider.builder()
            .realm(config.get("security.providers.0.http-basic-auth.realm").asString().get())
            .subjectType(SubjectType.USER)
            .userStore(store)
            .build();

    Security security = Security.builder()
            .config(config.get("security"))
            .addAuthenticationProvider(provider)
            .build();

    WebSecurity webSecurity = WebSecurity.create(security)
            .securityDefaults(WebSecurity.authenticate());

    Routing routing = Routing.builder()
            .register(webSecurity)
            .get("/", (request, response) -> response.send(config.get("app.greeting").asString().get() + "\n"))
            .get("/admin", (request, response) -> response.send("Greetings from the admin, " + users.get("admin").login() + "!\n"))
            .get("/user", (request, response) -> response.send("Greetings from the user, " + users.get("user").login() + "!\n"))
            .build();

    WebServer webServer = WebServer
            .create(serverConfig, routing)
            .start()
            .toCompletableFuture()
            .get(10, TimeUnit.SECONDS);

    System.out.println("INFO: Server started at: http://localhost:" + webServer.port() + "\n");
    }

与前面的示例一样,我们将构建实例变量configserverConfig 。 然后,我们使用getUsers()方法将角色映射到用户,用户。

使用Optional表示null类型安全性时,可通过SecureUserStore接口构建store实例变量,如lambda表达式所示。 安全的用户存储用于HTTP基本身份验证和HTTP摘要身份验证。 请记住,即使不需要与SSL一起使用,HTTP基本身份验证也可能是不安全的,因为不需要密码。

现在,我们准备构建HTTPBasicAuthProvider ,的实例,该实例是SecurityProvider接口的实现类之一。 realm()方法定义未经身份验证时发送到浏览器(或任何其他客户端)的安全领域名称。 由于我们在配置文件中定义了一个领域,因此将其传递到方法中。 subjectType()方法定义安全提供程序将提取或传播的主体类型。 它接受两个SubjectType枚举之一,即USERSERVICEuserStore()方法接受我们为验证应用程序中的用户而构建的store实例变量。

使用我们的provider实例变量,我们现在可以构建Security类的实例,该实例用于引导安全性并将其与其他框架集成。 我们使用config()addAuthenticationProvider()方法来完成此任务。 请注意,可以通过将其他addAuthenticationProvider()方法链接在一起来注册多个安全提供程序。 例如,假设我们定义了实例变量basicProviderdigestProvider ,分别代表HttpBasicAuthProviderHttpDigestAuthProvider类。 我们的security实例变量可以如下构建:

Security security = Security.builder()
        .config(config.get("security"))
        .addAuthenticationProvider(basicProvider)
        .addAuthenticationProvider(digestProvider)
        .build();

WebSecurity类实现了Service接口,该接口封装了一组路由规则和相关逻辑。 实例变量webSecurity是使用create()方法构建的,方法是传入security实例变量,然后将WebSecurity.authentic()方法传入securityDefaults()方法,以确保请求将通过身份验证过程。

我们在前面两个示例中构建的熟悉的实例变量routing看起来现在大不相同了。 它注册了webSecurity实例变量,并通过将get()方法链接在一起get()定义端点' / ',' /admin '和' /user '。 请注意, /admin/user端点分别绑定到用户benmike

终于,我们的网络服务器可以启动了! 在我们刚刚实施了所有机制之后,构建Web服务器看起来与前面的示例完全一样。

现在,我们可以使用相同的Maven和Java命令构建并运行此版本的Web服务器应用程序,并执行以下curl命令:

$ curl -X GET http://localhost:8080/将返回“ 来自Web服务器的问候!

$ curl -X GET http://localhost:8080/admin将返回“ 来自管理员的问候,本!

$ curl -X GET http://localhost:8080/user将返回“ 来自用户的问候,迈克!

您可以找到一个全面的服务器应用程序 ,该应用程序演示了与我们刚刚探讨的三个核心Helidon SE组件相关的startServer()方法的所有三个版本。 您还可以找到更详尽的Helidon 安全示例 ,这些示例将向您展示如何实现其他一些安全提供程序。

Helidon MP

Helidon MP建立在Helidon SE之上,是一个小型的声明式API,它是MicroProfile规范的实现,该规范针对微服务架构优化了企业Java,以构建基于微服务的应用程序。 MicroProfile计划于2016年由IBM,Red Hat,Payara和Tomitribe组成的合作组织成立,它指定了三个原始API-CDI( JSR 365 ),JSON-P( JSR 374 )和JAX-RS( JSR-370 )-用于创建微服务应用程序的API数量最少。 从那时起,MicroProfile已发展到12个核心API以及四个独立API,以支持响应流和GraphQL。 最新版本是2020年2月发布的MicroProfile 3.3。

Helidon MP当前支持MicroProfile 3.2。 对于Java EE / Jakarta EE开发人员来说,Helidon MP是一个绝佳的选择,因为它熟悉了使用注释的声明方法。 没有部署模型,也不需要其他Java EE打包。

让我们看一下有关启动Helidon Web服务器的非常简单的示例的Helidon MP的声明式样式,以及它如何与Helidon SE的功能样式进行比较。

public class GreetService {
  @GET
  @Path("/greet")
  public String getMsg() {
    return "Hello World!";
    }
  }

请注意,此样式与Helidon SE功能样式相比有所不同。

直升机场建筑

既然已经向您介绍了Helidon SE和Helidon MP,那么让我们看看它们如何结合在一起。 下图显示了Helidon的体系结构。 Helidon MP建立在Helidon SE之上,CDI扩展(将在下一部分中进行说明)扩展了Helidon MP的云原生功能。

CDI扩展

Helidon附带了可移植的上下文和依赖项注入(CDI) 扩展 ,这些扩展支持各种数据源,事务和客户端的集成,以扩展Helidon MP应用程序的云原生功能。 提供了以下扩展:

Helidon快速入门指南

Helidon提供了有关Helidon SEHelidon MP的快速入门指南。 只需访问这些页面并按照说明进行操作即可。 例如,您只需在终端窗口中执行以下Maven命令即可快速构建Helidon SE应用程序:

$ mvn archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-quickstart-se \
    -DarchetypeVersion=1.4.4 \
    -DgroupId=io.helidon.examples \
    -DartifactId=helidon-quickstart-se \
    -Dpackage=io.helidon.examples.quickstart.se

这将在文件夹helidon-quickstart-se生成一个小的但正在运行的应用程序,其中包括该应用程序的测试和配置文件(application.yaml ),日志记录( logging.properties ),并使用GraalVM构建本机映像( native-image.properties ),使用Docker( DockerfileDockerfile.native )对应用程序进行容器化,并使用Kubernetes( app.yaml )进行编排。

同样,您可以快速构建Helidon MP应用程序:

$ mvn archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=io.helidon.archetypes \
    -DarchetypeArtifactId=helidon-quickstart-mp \
    -DarchetypeVersion=1.4.4 \
    -DgroupId=io.helidon.examples \
    -DartifactId=helidon-quickstart-mp \
    -Dpackage=io.helidon.examples.quickstart.mp

这是构建更复杂的Helidon应用程序的一个很好的起点,我们将在下一部分中进行讨论。

电影申请

使用生成的Helidon MP快速入门应用程序,添加了其他类-POJO,资源,存储库,自定义异常以及ExceptionMapper的实现-以构建维护完整的Quentin Tarantino电影列表的电影应用程序 。 如下所示的HelidonApplication类注册所需的类。

@ApplicationScoped
@ApplicationPath("/")
public class HelidonApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> set = new HashSet<>();
        set.add(MovieResource.class);
        set.add(MovieNotFoundExceptionMapper.class);
        return Collections.unmodifiableSet(set);
        }
    }

您可以克隆GitHub 存储库以了解有关该应用程序的更多信息。

GraalVM

Helidon支持GraalVM (一个多语言虚拟机和平台),可将应用程序转换为本地可执行代码。 由Oracle Labs创建的GraalVM包括用Java编写的即时编译器Graal ,允许提前将Java应用程序编译成可执行映像的框架SubstrateVM和开源工具箱Truffle 。和用于构建语言解释器的API。 最新版本是20.1.0。

您可以使用GraalVM的native-image实用程序将Helidon SE应用程序转换为本地可执行代码,该实用程序是使用GraalVM的gu实用程序进行的单独安装:

$ gu install native-image
$ export
GRAALVM_HOME=/usr/local/bin/graalvm-ce-java11-20.1.0/Contents/Home

安装后,您可以返回到helidon-quickstart-se目录并执行以下命令:

$ mvn package -Pnative-image

此操作将花费几分钟,但是一旦完成,您的应用程序将转换为本机代码。 可执行文件位于/target目录中。

通往Helidon 2.0之路

Helidon 2.0.0计划于2020年Spring末发布,此时开发人员可以使用Helidon 2.0.0.RC1 。 重要的新功能包括在Helidon MP应用程序上支持GraalVM,新的Web客户端和数据库客户端组件,新的CLI工具以及独立的MicroProfile React消息React流操作程序 API的实现。

直到最近,由于在核心MicroProfile API CDI 2.0( JSR 365 )中使用了反射,只有Helidon SE应用程序才能够利用GraalVM。 但是,由于客户需求,Helidon 2.0.0将支持将Helidon MP应用程序转换为本地映像。 Oracle已为Java社区创建了该演示应用程序 ,以预览此新功能。

为了补充最初的三个核心Helidon SE API(Web服务器,配置和安全性),新的Web客户端 API完善了Helidon SE的功能。 通过构建WebClient接口的实例,您可以处理与指定端点有关的HTTP请求和响应。 就像Web服务器API一样,Web客户端也可以通过配置文件进行配置。

您可以在即将发布的Helidon 2.0.0的GA版本中了解有关开发人员期望的更多详细信息

翻译自: https://www.infoq.com/articles/helidon-tutorial/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

helidon使用

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值