1. 概述

随着微服务架构和云原生应用的普及,开发者对轻量、快速启动的应用服务器需求日益增长。

本文将带你快速入门 Open Liberty 框架,学会如何创建和消费一个 RESTful 接口。我们还会介绍它的一些核心特性,帮助你在实际项目中快速上手。

2. Open Liberty 简介

Open Liberty 是 一个面向 Java 生态的开源框架,支持基于 Eclipse MicroProfileJakarta EE 构建微服务

它是一个灵活、轻量且启动迅速的 Java 运行时,非常适合云原生微服务开发。

✅ 核心优势:

  • 按需启用功能模块,只加载应用所需特性,显著降低内存占用
  • 支持 Docker、Kubernetes 等主流容器平台部署
  • 开发模式支持热加载,代码修改后自动生效,无需重启

这种“按需组装”的设计,让应用更轻、启动更快,是构建现代微服务的理想选择。

3. 构建与运行

我们先创建一个名为 open-liberty 的 Maven 项目,然后在 pom.xml 中引入 liberty-maven-plugin 插件:

<plugin>
    <groupId>io.openliberty.tools</groupId>
    <artifactId>liberty-maven-plugin</artifactId>
    <version>3.3-M3</version>
</plugin>

或者,你也可以选择使用 openliberty-runtime 依赖替代插件:

<dependency>
    <groupId>io.openliberty</groupId>
    <artifactId>openliberty-runtime</artifactId>
    <version>20.0.0.1</version>
    <type>zip</type>
</dependency>

Gradle 用户可以在 build.gradle 中添加:

dependencies {
    libertyRuntime group: 'io.openliberty', name: 'openliberty-runtime', version: '20.0.0.1'
}

接着,引入 Jakarta EE Web API 和 MicroProfile 依赖:

<dependency>
    <groupId>jakarta.platform</groupId>
    <artifactId>jakarta.jakartaee-web-api</artifactId>
    <version>8.0.0</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.eclipse.microprofile</groupId>
    <artifactId>microprofile</artifactId>
    <version>3.2</version>
    <type>pom</type>
    <scope>provided</scope>
</dependency>

配置默认端口:

<properties>
    <liberty.var.default.http.port>9080</liberty.var.default.http.port>
    <liberty.var.default.https.port>9443</liberty.var.default.https.port>
</properties>

src/main/liberty/config 目录下创建 server.xml

<server description="Baeldung Open Liberty server">
    <featureManager>
        <feature>mpHealth-2.0</feature>
    </featureManager>
    <webApplication location="open-liberty.war" contextRoot="/" />
    <httpEndpoint host="*" httpPort="${default.http.port}" 
      httpsPort="${default.https.port}" id="defaultHttpEndpoint" />
</server>

⚠️ 注意:mpHealth-2.0 是 MicroProfile Health 功能,用于健康检查。

完成配置后,执行编译:

mvn clean package

启动开发服务器:

mvn liberty:dev

✅ 应用启动成功,访问 http://localhost:9080 可看到默认页面:

Screen-Shot-2020-01-15-at-1.46.17-PM

健康检查接口:http://localhost:9080/health

{"checks":[],"status":"UP"}

💡 liberty:dev 命令会以开发模式启动,支持热加载。生产环境建议使用 liberty:run

其他常用命令:

  • liberty:start-server:后台启动
  • liberty:stop-server:停止服务器

4. Servlet 使用

要在项目中使用 Servlet,需在 server.xml 中启用 servlet-4.0 功能:

<featureManager>
    ...
    <feature>servlet-4.0</feature>
</featureManager>

如果使用 openliberty-runtime 依赖,还需添加 Maven 依赖:

<dependency>
    <groupId>io.openliberty.features</groupId>
    <artifactId>servlet-4.0</artifactId>
    <version>20.0.0.1</version>
    <type>esa</type>
</dependency>

⚠️ 使用 liberty-maven-plugin 则无需此依赖。

创建 AppServlet

@WebServlet(urlPatterns="/app")
public class AppServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, IOException {
        String htmlOutput = "<html><h2>Hello! Welcome to Open Liberty</h2></html>";
        response.getWriter().append(htmlOutput);
    }
}

@WebServlet 注解将 Servlet 映射到 /app 路径。

访问 http://localhost:9080/app 查看效果:

Screen-Shot-2020-01-18-at-4.21.46-PM

5. 创建 RESTful 接口

首先在 server.xml 中启用 JAX-RS 功能:

<featureManager>
    ...
    <feature>jaxrs-2.1</feature>
</featureManager>

创建 ApiApplication 类定义接口根路径:

@ApplicationPath("/api")
public class ApiApplication extends Application {
}

定义 Person 模型类:

public class Person {
    private String username;
    private String email;

    // getters and setters
    // constructors
}

创建 PersonResource 接口类:

@RequestScoped
@Path("persons")
public class PersonResource {
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Person> getAllPersons() {
        return Arrays.asList(new Person(1, "normanlewis", "norman@example.com"));
    }
}

✅ 此接口可通过 http://localhost:9080/api/persons 访问。

使用 curl 测试:

curl --request GET --url http://localhost:9080/api/persons

响应:

[{"id":1, "username":"normanlewis", "email":"norman@example.com"}]

添加 POST 接口:

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response addPerson(Person person) {
    String respMessage = "Person " + person.getUsername() + " received successfully.";
    return Response.status(Response.Status.CREATED).entity(respMessage).build();
}

调用 POST 接口:

curl --request POST --url http://localhost:9080/api/persons \
  --header 'content-type: application/json' \
  --data '{"username": "normanlewis", "email": "norman@example.com"}'

响应:

Person normanlewis received successfully.

6. 持久化支持

6.1 配置

为接口添加数据库支持。

添加 Derby 依赖:

<dependency>
    <groupId>org.apache.derby</groupId>
    <artifactId>derby</artifactId>
    <version>10.14.2.0</version>
</dependency>

server.xml 中启用 JPA、JSON-P 和 CDI 功能:

<featureManager>
    ...
    <feature>jpa-2.2</feature> 
    <feature>jsonp-1.1</feature>
    <feature>cdi-2.0</feature>
</featureManager>

创建 persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd">
    <persistence-unit name="jpa-unit" transaction-type="JTA">
        <jta-data-source>jdbc/jpadatasource</jta-data-source>
        <properties>
            <property name="eclipselink.ddl-generation" value="create-tables"/>
            <property name="eclipselink.ddl-generation.output-mode" value="both" />
        </properties>
    </persistence-unit>
</persistence>

配置数据源:

<library id="derbyJDBCLib">
    <fileset dir="${shared.resource.dir}" includes="derby*.jar"/> 
</library>
<dataSource id="jpadatasource" jndiName="jdbc/jpadatasource">
    <jdbcDriver libraryRef="derbyJDBCLib" />
    <properties.derby.embedded databaseName="libertyDB" createDatabase="create" />
</dataSource>

⚠️ 注意 jndiName 需与 persistence.xml 中的 jta-data-source 一致。

6.2 实体与 DAO

改造 Person 类为 JPA 实体:

@Entity
public class Person {
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    private int id;
    
    private String username;
    private String email;

    // getters and setters
}

创建 PersonDao

@RequestScoped
public class PersonDao {
    @PersistenceContext(name = "jpa-unit")
    private EntityManager em;

    public Person createPerson(Person person) {
        em.persist(person);
        return person;
    }

    public Person readPerson(int personId) {
        return em.find(Person.class, personId);
    }
}

PersonResource 中注入 DAO:

@RequestScoped
@Path("persons")
public class PersonResource {
    @Inject
    private PersonDao personDao;

    // ...
}

更新 addPerson 方法实现持久化:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Transactional
public Response addPerson(Person person) {
    personDao.createPerson(person);
    String respMessage = "Person #" + person.getId() + " created successfully.";
    return Response.status(Response.Status.CREATED).entity(respMessage).build();
}

测试 POST 请求:

curl --request POST --url http://localhost:9080/api/persons \
  --header 'content-type: application/json' \
  --data '{"username": "normanlewis", "email": "norman@example.com"}'

响应:

Person #1 created successfully.

添加 GET 单个资源接口:

@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)
@Transactional
public Person getPerson(@PathParam("id") int id) {
    Person person = personDao.readPerson(id);
    return person;
}

测试:

curl --request GET --url http://localhost:9080/api/persons/1

响应:

{"email":"norman@example.com","id":1,"username":"normanlewis"}

7. 使用 JSON-B 消费 REST 接口

启用 JSON-B 功能:

<featureManager>
    ...
    <feature>jsonb-1.0</feature>
</featureManager>

创建 RestConsumer

public class RestConsumer {
    public static String consumeWithJsonb(String targetUrl) {
        Client client = ClientBuilder.newClient();
        Response response = client.target(targetUrl).request().get();
        String result = response.readEntity(String.class);
        response.close();
        client.close();
        return result;
    }
}

编写测试用例:

@Test
public void whenConsumeWithJsonb_thenGetPerson() {
    String url = "http://localhost:9080/api/persons/1";
    String result = RestConsumer.consumeWithJsonb(url);        
    
    Person person = JsonbBuilder.create().fromJson(result, Person.class);
    assertEquals(1, person.getId());
    assertEquals("normanlewis", person.getUsername());
    assertEquals("norman@example.com", person.getEmail());
}

💡 提示:你也可以使用 MicroProfile Rest Client(添加 mpRestClient-1.3 功能),它提供了更优雅的声明式 REST 调用方式。

8. 总结

本文介绍了 Open Liberty —— 一个轻量、高性能的 Java 运行时,完整支持 Eclipse MicroProfile 和 Jakarta EE 特性。

我们完成了以下实践:

  • ✅ 使用 JAX-RS 构建 RESTful 接口
  • ✅ 集成 JPA + CDI 实现数据持久化
  • ✅ 使用 JSON-B 消费外部接口

Open Liberty 的模块化设计和开发友好性,让它成为构建云原生微服务的有力工具。

所有示例代码已上传至 GitHub:https://github.com/eugenp/tutorials/tree/master/microservices-modules/open-liberty


原始标题:Introduction to Open Liberty | Baeldung