Introduction to Open Liberty – 开放自由的介绍

最后修改: 2020年 2月 3日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

With the popularity of microservice architecture and cloud-native application development, there’s a growing need for a fast and lightweight application server.

随着微服务架构和云原生应用开发的普及,人们对快速和轻量级应用服务器的需求越来越大。

In this introductory tutorial, we’ll explore the Open Liberty framework to create and consume a RESTful web service. We’ll also examine a few of the essential features that it provides.

在这个介绍性教程中,我们将探讨Open Liberty框架,以创建和消费RESTful Web服务。我们还将研究它所提供的一些基本功能。

2. Open Liberty

2.开放的自由

Open Liberty is an open framework for the Java ecosystem that allows developing microservices using features of the Eclipse MicroProfile and Jakarta EE platforms.

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

It is a flexible, fast, and lightweight Java runtime that seems promising for cloud-native microservices development.

它是一个灵活、快速、轻量级的Java运行时,似乎对云原生微服务开发很有希望。

The framework allows us to configure only the features our app needs, resulting in a smaller memory footprint during startup. Also, it is deployable on any cloud platform using containers like Docker and Kubernetes.

该框架允许我们只配置我们的应用程序所需的功能,从而在启动时产生较小的内存占用。而且,它可以使用DockerKubernetes等容器在任何云平台上进行部署。

It supports rapid development by live reloading of the code for quick iteration.

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

3. Build and Run

3.建立和运行

First, we’ll create a simple Maven-based project named open-liberty and then add the latest liberty-maven-plugin plugin to the pom.xml:

首先,我们将创建一个名为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>

Or, we can add the latest openliberty-runtime Maven dependency as an alternative to the liberty-maven-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>

Similarly, we can add the latest Gradle dependency to the build.gradle:

同样地,我们可以在build.gradle中添加最新的Gradle依赖项。

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

Then, we’ll add the latest jakarta.jakartaee-web-api and microprofile Maven dependencies:

然后,我们将添加最新的jakarta.jakartaee-web-apimicroprofileMaven依赖项。

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

Then, let’s add the default HTTP port properties to the pom.xml:

然后,让我们把默认的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>

Next, we’ll create the server.xml file in the src/main/liberty/config directory:

接下来,我们将在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>

Here, we’ve added the mpHealth-2.0 feature to check the health of the application.

在这里,我们添加了mpHealth-2.0功能来检查应用程序的健康状况。

That’s it with all the basic setup. Let’s run the Maven command to compile the files for the first time:

所有的基本设置就这样完成了。让我们运行Maven命令,首次编译这些文件。

mvn clean package

Last, let’s run the server using a Liberty-provided Maven command:

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

mvn liberty:dev

Voila! Our application is started and will be accessible at localhost:9080:

看吧!我们的应用程序已经启动,并可在localhost:9080处访问。

Also, we can access the health of the app at localhost:9080/health:

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

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

The liberty:dev command starts the Open Liberty server in development mode, which hot-reloads any changes made to the code or configuration without restarting the server.

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

Similarly, the liberty:run command is available to start the server in production mode.

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

Also, we can use liberty:start-server and liberty:stop-server to start/stop the server in the background.

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

4. Servlet

4.Servlet

To use servlets in the app, we’ll add the servlet-4.0 feature to the server.xml:

为了在应用程序中使用servlets,我们将在servlet-4.0中添加server.xml功能。

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

Add the latest servlet-4.0 Maven dependency if using the openliberty-runtime Maven dependency in the pom.xml:

如果在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>

However, if we’re using the liberty-maven-plugin plugin, this isn’t necessary.

不过,如果我们使用liberty-maven-plugin插件,就没有必要这样做了。

Then, we’ll create the AppServlet class extending the HttpServlet class:

然后,我们将创建AppServlet类,扩展HttpServlet类。

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

Here, we’ve added the @WebServlet annotation that will make the AppServlet available at the specified URL pattern.

在这里,我们添加了@WebServlet注解,这将使AppServlet在指定的URL模式中可用。

Let’s access the servlet at localhost:9080/app:

让我们访问位于localhost:9080/app的servlet。

5. Create a RESTful Web Service

5.创建一个RESTful网络服务

First, let’s add the jaxrs-2.1 feature to the server.xml:

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

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

Then, we’ll create the ApiApplication class, which provides endpoints to the RESTful web service:

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

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

Here, we’ve used the @ApplicationPath annotation for the URL path.

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

Then, let’s create the Person class that serves the model:

然后,让我们创建为该模型服务的Person 类。

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

    // getters and setters
    // constructors
}

Next, we’ll create the PersonResource class to define the HTTP mappings:

接下来,我们将创建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"));
    }
}

Here, we’ve added the getAllPersons method for the GET mapping to the /api/persons endpoint. So, we’re ready with a RESTful web service, and the liberty:dev command will load changes on-the-fly.

在这里,我们为GET映射添加了/api/persons端点的getAllPersons方法。所以,我们已经准备好了一个RESTful网络服务,liberty:dev命令将即时加载变化。

Let’s access the /api/persons RESTful web service using a curl GET request:

让我们使用curl GET请求访问/api/persons RESTful网络服务。

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

Then, we’ll get a JSON array in response:

然后,我们会得到一个JSON数组作为回应。

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

Similarly, we can add the POST mapping by creating the addPerson method:

同样地,我们可以通过创建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();
}

Now, we can invoke the endpoint with a curl POST request:

现在,我们可以用curl POST请求来调用这个端点。

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

The response will look like:

响应将看起来像。

Person normanlewis received successfully.

6. Persistence

6.坚持不懈

6.1. Configuration

6.1.配置

Let’s add persistence support to our RESTful web services.

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

First, we’ll add the derby Maven dependency to the pom.xml:

首先,我们要把derby Maven依赖性添加到pom.xml

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

Then, we’ll add a few features like jpa-2.2, jsonp-1.1, and cdi-2.0 to the server.xml:

然后,我们将在server.xml中添加一些功能,如jpa-2.2jsonp-1.1cdi-2.0

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

Here, the jsonp-1.1 feature provides the Java API for JSON Processing, and the cdi-2.0 feature handles the scopes and dependency injection.

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

Next, we’ll create the persistence.xml in the src/main/resources/META-INF directory:

接下来,我们将在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>

Here, we’ve used the EclipseLink DDL generation to create our database schema automatically. We can also use other alternatives like Hibernate.

在这里,我们使用了EclipseLink DDL生成来自动创建我们的数据库模式。我们也可以使用其他替代品,如Hibernate。

Then, let’s add the dataSource configuration to the server.xml:

然后,让我们把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>

Note, the jndiName has the same reference to the jta-data-source tag in the persistence.xml.

注意,jndiNamepersistence.xml.中的jta-data-source标签有相同的引用。

6.2. Entity and DAO

6.2.实体和DAO

Then, we’ll add the @Entity annotation and an identifier to our Person class:

然后,我们将添加@Entity注解和一个标识符到我们的Person类。

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

    // getters and setters
}

Next, let’s create the PersonDao class that will interact with the database using the EntityManager instance:

接下来,让我们创建PersonDao类,它将使用EntityManager实例与数据库交互。

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

Note that the @PersistenceContext defines the same reference to the persistence-unit tag in the persistence.xml.

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

Now, we’ll inject the PersonDao dependency in the PersonResource class:

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

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

    // ...
}

Here, we’ve used the @Inject annotation provided by the CDI feature.

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

Last, we’ll update the addPerson method of the PersonResource class to persist the Person object:

最后,我们将更新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();
}

Here, the addPerson method is annotated with the @Transactional annotation to control transactions on CDI managed beans.

这里,addPerson方法被注解为@Transactional注解,以控制CDI托管Bean上的事务。

Let’s invoke the endpoint with the already discussed curl POST request:

让我们用已经讨论过的curl POST请求来调用这个端点。

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

Then, we’ll receive a text response:

然后,我们会收到一个短信回复。

Person #1 created successfully.

Similarly, let’s add the getPerson method with GET mapping to fetch a Person object:

同样,让我们添加带有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;
}

Let’s invoke the endpoint using a curl GET request:

让我们用curl GET请求来调用这个端点。

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

Then, we’ll get the Person object as JSON response:

然后,我们将得到Person对象作为JSON响应。

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

7. Consume RESTful Web Service Using JSON-B

7.使用JSON-B消耗RESTful网络服务

First, we’ll enable the ability to directly serialize and deserialize models by adding the jsonb-1.0 feature to the server.xml:

首先,我们将通过在server.xml中添加jsonb-1.0功能,使其能够直接序列化和反序列化模型。

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

Then, let’s create the RestConsumer class with the consumeWithJsonb method:

然后,让我们用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;
    }
}

Here, we’ve used the ClientBuilder class to request the RESTful web service endpoints.

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

Last, let’s write a unit test to consume the /api/person RESTful web service and verify the response:

最后,让我们写一个单元测试来消费/api/person RESTful网络服务并验证响应。

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

Here, we’ve used the JsonbBuilder class to parse the String response into the Person object.

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

Also, we can use MicroProfile Rest Client by adding the mpRestClient-1.3 feature to consume the RESTful web services. It provides the RestClientBuilder interface to request the RESTful web service endpoints.

另外,我们可以通过添加mpRestClient-1.3功能来使用MicroProfile Rest Client,以消费RESTful web服务。它提供了RestClientBuilder接口来请求RESTful web服务端点。

8. Conclusion

8.结语

In this article, we explored the Open Liberty framework — a fast and lightweight Java runtime that provides full features of the Eclipse MicroProfile and Jakarta EE platforms.

在这篇文章中,我们探讨了Open Liberty框架–一个快速和轻量级的Java运行时,提供了Eclipse MicroProfile和Jakarta EE平台的全部功能。

To begin with, we created a RESTful web service using JAX-RS. Then, we enabled persistence using features like JPA and CDI.

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

Last, we consumed the RESTful web service using JSON-B.

最后,我们使用JSON-B来消费RESTful网络服务。

As usual, all the code implementations are available over on GitHub.

像往常一样,所有的代码实现都可以在GitHub上找到