1. 概述

Helidon 是 Oracle 最近开源的一款用于构建 Java 微服务的轻量级框架,此前主要用于 Oracle 内部的 J4C(Java for Cloud)项目。

本篇文章将带你了解 Helidon 的核心概念,并通过示例演示如何使用 Helidon 构建并运行一个微服务应用。

2. 编程模型

目前,Helidon 提供了两种微服务编程模型:

Helidon SE:基于反应式编程模型的轻量级微框架
Helidon MP:基于 Eclipse MicroProfile 的运行时,兼容 Jakarta EE 社区标准

⚠️ 无论使用哪种模型,Helidon 微服务本质上都是一个 Java SE 应用程序,它通过 main 方法启动一个轻量级 HTTP 服务器。

3. Helidon SE

Helidon SE 的核心组件包括:WebServer、Config、Security。

3.1. 配置 WebServer

首先,我们需要在 pom.xml 中添加 Helidon WebServer 的依赖:

<dependency>
    <groupId>io.helidon.webserver</groupId>
    <artifactId>helidon-webserver</artifactId>
    <version>3.2.2</version>
</dependency>

要创建一个简单的 Web 应用,可以使用以下方式之一:

  • WebServer.create(routing, serverConfig)
  • WebServer.create(routing)(使用默认配置,随机端口)

示例:一个监听在 9001 端口的 Web 服务,处理 /greet 路径的 GET 请求:

public static void main(String... args) throws Exception {
    Routing routing = Routing.builder()
      .get("/greet", (request, response) -> response.send("Hello World !")).build();

    WebServer.builder(routing)
      .port(9001).addRouting(routing).build()
      .start()
      .thenAccept(ws ->
          System.out.println("Server started at: http://localhost:" + ws.port())
      );
}

⚠️ 如果直接运行上述代码,会报错:

Exception in thread "main" java.lang.IllegalStateException: 
  No implementation found for SPI: io.helidon.webserver.spi.WebServerFactory

这是因为 WebServer 是一个 SPI 接口,需要提供具体实现。Helidon 默认使用基于 Netty 的实现:

<dependency>
    <groupId>io.helidon.webserver</groupId>
    <artifactId>helidon-webserver-netty</artifactId>
    <version>0.10.6</version>
    <scope>runtime</scope>
</dependency>

✅ 添加依赖后就可以启动服务,并通过以下 URL 测试:

http://localhost:9001/greet

3.2. Config API

Config API 用于读取配置数据,支持多种配置源。默认配置文件为 application.properties,位于 classpath 下。

添加依赖:

<dependency>
    <groupId>io.helidon.config</groupId>
    <artifactId>helidon-config</artifactId>
    <version>3.2.2</version>
</dependency>

读取配置:

Config config = Config.builder().build();

示例配置文件 application.properties

server.port=9080
web.debug=true
web.page-size=15
user.home=C:/Users/app

获取配置值:

int port = config.get("server.port").asInt().get();
int pageSize = config.get("web.page-size").asInt().get();
boolean debug = config.get("web.debug").asBoolean().get();
String userHome = config.get("user.home").asString().get();

✅ 支持的配置文件格式(优先级顺序):

  • application.yaml
  • application.conf
  • application.json
  • application.properties

如需使用 YAML 格式,添加依赖:

<dependency>
    <groupId>io.helidon.config</groupId>
    <artifactId>helidon-config-yaml</artifactId>
    <version>3.2.2</version>
</dependency>

示例 application.yml

server:
  port: 9080  
web:
  debug: true
  page-size: 15
user:
  home: C:/Users/app

✅ 可通过环境变量或系统属性覆盖配置项。

也可以自定义配置源,例如从 Git 或 etcd 加载配置。

3.3. Routing API

Routing API 用于将 HTTP 请求映射到 Java 方法。

✅ 简单路由:

Routing routing = Routing.builder()
  .get("/path", (request, response) -> {} );

✅ 使用 RequestPredicate 添加更多匹配条件:

Routing routing = Routing.builder()
  .post("/save",
    RequestPredicate.whenRequest()
      .containsHeader("header1")
      .containsCookie("cookie1")
      .accepts(MediaType.APPLICATION_JSON)
      .containsQueryParameter("param1")
      .hasContentType("application/json")
      .thenApply((request, response) -> { })
      .otherwise((request, response) -> { }))
      .build();

✅ 使用 Service 类实现 REST 接口:

public class BookResource implements Service {

    private BookManager bookManager = new BookManager();

    @Override
    public void update(Routing.Rules rules) {
        rules
          .get("/", this::books)
          .get("/{id}", this::bookById);
    }

    private void bookById(ServerRequest serverRequest, ServerResponse serverResponse) {
        String id = serverRequest.path().param("id");
        Book book = bookManager.get(id);
        JsonObject jsonObject = from(book);
        serverResponse.send(jsonObject);
    }

    private void books(ServerRequest serverRequest, ServerResponse serverResponse) {
        List<Book> books = bookManager.getAll();
        JsonArray jsonArray = from(books);
        serverResponse.send(jsonArray);
    }
}

✅ 添加 JSON 支持依赖:

<dependency>
    <groupId>io.helidon.webserver</groupId>
    <artifactId>helidon-webserver-json</artifactId>
    <version>0.11.0</version>
</dependency>

注册路由:

Routing routing = Routing.builder()
  .register(JsonSupport.get())
  .register("/books", new BookResource())
  .build();

访问接口:

http://localhost:9080/books
http://localhost:9080/books/0001-201810

3.4. 安全模块 Security

✅ 添加依赖:

<dependency>
    <groupId>io.helidon.security</groupId>
    <artifactId>helidon-security</artifactId>
    <version>3.2.2</version>
</dependency>
<dependency>
    <groupId>io.helidon.security.providers</groupId>
    <artifactId>helidon-security-providers-http-auth</artifactId>
    <version>3.2.2</version>
</dependency>
<dependency>
    <groupId>io.helidon.security.integration</groupId>
    <artifactId>helidon-security-integration-webserver</artifactId>
    <version>3.2.2</version>
</dependency>

✅ 简单配置方式:

Map<String, MyUser> users = //...
SecureUserStore store = user -> Optional.ofNullable(users.get(user));

HttpBasicAuthProvider httpBasicAuthProvider = HttpBasicAuthProvider.builder()
  .realm("myRealm")
  .subjectType(SubjectType.USER)
  .userStore(store)
  .build();

Security security = Security.builder()
  .addAuthenticationProvider(httpBasicAuthProvider)
  .build();

✅ 或通过 application.yml 配置:

security:
  providers:
  - http-basic-auth:
      realm: "helidon"
      principal-type: USER
      users:
      - login: "user"
        password: "user"
        roles: ["ROLE_USER"]
      - login: "admin"
        password: "admin"
        roles: ["ROLE_USER", "ROLE_ADMIN"]

  web-server:
    securityDefaults:
      authenticate: true
    paths:
    - path: "/user"
      methods: ["get"]
      roles-allowed: ["ROLE_USER", "ROLE_ADMIN"]
    - path: "/admin"
      methods: ["get"]
      roles-allowed: ["ROLE_ADMIN"]

加载配置并注册安全模块:

Config config = Config.create();
Security security = Security.fromConfig(config);

Routing routing = Routing.builder()
  .register(WebSecurity.create(config))
  .get("/user", (request, response) -> response.send("Hello, I'm Helidon SE"))
  .get("/admin", (request, response) -> response.send("Hello, I'm Helidon SE"))
  .build();

4. Helidon MP

✅ Helidon MP 是 Eclipse MicroProfile 的实现,可用于运行任何兼容 MicroProfile 的微服务。

添加依赖:

<dependency>
    <groupId>io.helidon.microprofile.bundles</groupId>
    <artifactId>helidon-microprofile</artifactId>
    <version>3.2.2</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-binding</artifactId>
    <version>3.1.2</version>
</dependency>

✅ 添加 beans.xml 文件:

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
  http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
  version="2.0" bean-discovery-mode="annotated">
</beans>

✅ 启动服务:

public static void main(String... args) {
    Server server = Server.builder()
      .addApplication(LibraryApplication.class)
      .port(9080)
      .build();
    server.start();
}

5. 总结

本文介绍了 Helidon 的主要组件,展示了如何使用 Helidon SE 和 MP 构建微服务。Helidon MP 作为 Eclipse MicroProfile 的运行时,兼容性良好,可运行现有 MicroProfile 微服务。

✅ 示例代码可在 GitHub 获取。


原始标题:Microservices with Oracle Helidon