Open Liberty简介

2023/05/20

1. 概述

随着微服务架构和云原生应用程序开发的流行,对快速、轻量级应用服务器的需求越来越大。

在本介绍性教程中,我们将探索Open Liberty框架来创建和使用RESTful Web服务。我们还将研究它提供的一些基本功能。

2. Open Liberty

Open Liberty是Java生态系统的开放框架,允许使用Eclipse MicroProfileJakarta EE平台的功能开发微服务

它是一种灵活、快速且轻量级的Java运行时,对于云原生微服务开发似乎很有前途。

该框架允许我们仅配置我们的应用程序需要的功能,从而在启动期间占用更少的内存。此外,它可以部署在任何使用DockerKubernetes等容器的云平台上。

它通过实时重新加载代码以实现快速迭代来支持快速开发。

3. 构建并运行

首先,我们将创建一个名为open-liberty的简单的基于Maven的项目,然后将最新的liberty-maven-plugin插件添加到pom.xml中:

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

或者,我们可以添加最新的openliberty-runtime Maven依赖项作为liberty-maven-plugin的替代方案:

<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.jakartaee-web-apimicroprofile Maven依赖项:

<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>

然后,让我们将默认的HTTP端口属性添加到pom.xml中:

<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功能来检查应用程序的运行状况。

这就是所有基本设置。让我们运行Maven命令来首次编译文件:

mvn clean package

最后,让我们使用Liberty提供的Maven命令运行服务器:

mvn liberty:dev

现在我们的应用程序已启动,可以在localhost:9080访问:

此外,我们可以在localhost:9080/health访问应用程序的健康状况:

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

liberty:dev命令以开发模式启动Open Liberty服务器,它会热重载对代码或配置所做的任何更改,而无需重新启动服务器。

同样,liberty:run命令可用于在生产模式下启动服务器。

另外,我们可以使用liberty:start-server和liberty:stop-server在后台启动/停止服务器

4. Servlet

要在应用程序中使用Servlet,我们将servlet-4.0功能添加到server.xml:

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

如果在pom.xml中使用openliberty-runtime Maven依赖项,请添加最新的servlet-4.0 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插件,则没有必要这样做。

然后,我们将创建扩展HttpServlet类的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注解,这将使AppServlet在指定的URL模式下可用。

让我们在localhost:9080/app访问Servlet:

5. 创建RESTful Web服务

首先,让我们将jaxrs-2.1功能添加到server.xml中:

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

然后,我们将创建ApiApplication类,它为RESTful Web服务提供端点:

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

在这里,我们为URL路径使用了@ApplicationPath注解。

然后,让我们创建服务模型的Person类:

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

    // getters, setters and constructors
}

接下来,我们将创建PersonResource类来定义HTTP映射:

@RequestScoped
@Path("persons")
public class PersonResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Person> getAllPersons() {
        return Arrays.asList(new Person(1, "normanlewis", "normanlewis@email.com"));
    }
}

在这里,我们添加了getAllPersons方法,用于将GET映射到/api/people端点。因此,我们已准备好使用RESTful Web服务,并且liberty:dev命令将即时加载更改。

让我们使用curl GET请求访问/api/persons RESTful Web服务:

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

然后,我们将得到一个JSON数组作为响应:

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

同样,我们可以通过创建addPerson方法来添加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();
}

现在,我们可以使用curl POST请求调用端点:

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

响应将如下所示:

Person normanlewis received successfully.

6. 持久层

6.1 配置

让我们为RESTful Web服务添加持久性支持。

首先,我们将derby Maven依赖项添加到pom.xml中:

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

然后,我们将向server.xml添加一些功能,例如jpa-2.2、jsonp-1.1和cdi-2.0:

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

在这里,jsonp-1.1功能提供了用于JSON处理的Java API,而cdi-2.0功能处理作用域和依赖注入。

接下来,我们将在src/main/resources/META-INF目录中创建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>

在这里,我们使用了EclipseLink ddl-generation来自动创建我们的数据库模式。我们还可以使用其他替代方案,例如Hibernate。

然后,让我们将dataSource配置添加到server.xml:

<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

然后,我们将@Entity和相关注解添加到Person类:

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

    private String username;
    private String email;

    // getters and setters
}

接下来,让我们创建将使用EntityManager实例与数据库交互的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);
    }
}

请注意,@PersistenceContext定义了对persistence.xml中persistence-unit标签的相同引用

现在,我们将在PersonResource类中注入PersonDao依赖:

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

    // ...
}

在这里,我们使用了CDI功能提供的@Inject注解。

最后,我们将更新PersonResource类的addPerson方法来持久化Person对象:

@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();
}

此处,addPerson方法使用@Transactional注解进行标注,以控制CDI托管bean上的事务。

让我们使用已经讨论过的curl POST请求调用端点:

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

然后,我们将收到一条文本回复:

Person #1 created successfully.

同样,让我们添加带有GET映射的getPerson方法来获取Person对象:

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

让我们使用curl GET请求调用端点:

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

然后,我们将获取Person对象作为JSON响应:

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

7. 使用JSON-B使用RESTful Web服务

首先,我们将通过向server.xml添加jsonb-1.0功能来启用直接序列化和反序列化模型的能力:

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

然后,让我们使用consumeWithJsonb方法创建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;
    }
}

在这里,我们使用了ClientBuilder类来请求RESTful Web服务端点。

最后,让我们编写一个单元测试来使用/api/person RESTful Web服务并验证响应:

@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("normanlewis@email.com", person.getEmail());
}

在这里,我们使用JsonbBuilder类将String响应解析为Person对象。

此外,我们可以通过添加mpRestClient-1.3功能来使用MicroProfile RestClient来使用RESTful Web服务。它提供RestClientBuilder接口来请求RESTful Web服务端点。

8. 总结

在本文中,我们探索了Open Liberty框架-一个快速且轻量级的Java运行时,它提供了Eclipse MicroProfile和Jakarta EE平台的全部功能。

首先,我们使用JAX-RS创建了一个RESTful Web服务。然后,我们使用JPA和CDI等功能启用持久性。

最后,我们使用JSON-B使用RESTful Web服务。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章