Перейти к основному содержимому

Введение в открытую свободу

· 8 мин. чтения

1. Обзор

С ростом популярности микросервисной архитектуры и разработки облачных приложений растет потребность в быстром и легком сервере приложений.

В этом вводном руководстве мы рассмотрим платформу Open Liberty для создания и использования веб-службы RESTful. Мы также рассмотрим несколько основных функций, которые он предоставляет.

2. Открытая свобода

Open Liberty — это открытый фреймворк для экосистемы Java, позволяющий разрабатывать микросервисы с использованием возможностей платформ Eclipse MicroProfile и Jakarta EE .

Это гибкая, быстрая и легкая среда выполнения Java, которая кажется многообещающей для разработки облачных микросервисов.

Платформа позволяет нам настраивать только те функции, которые нужны нашему приложению, что приводит к меньшему объему памяти при запуске. Кроме того, его можно развернуть на любой облачной платформе с использованием таких контейнеров, как Docker и Kubernetes .

Он поддерживает быструю разработку за счет перезагрузки кода в реальном времени для быстрой итерации.

3. Создайте и запустите

Во-первых, мы создадим простой проект на основе Maven с именем open-liberty, а затем добавим в pom.xml последнюю версию плагина Liberty -maven-plugin : ``

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

Или мы можем добавить последнюю зависимость Maven openliberty-runtime в качестве альтернативы 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-api и microprofile 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>

Далее мы создадим файл server.xml в каталоге src/main/liberty/config :

<server description="ForEach 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 :

./871890f0af687d86adc6008af08e69cb.png

Кроме того, мы можем получить доступ к состоянию приложения по адресу localhost:9080/health :

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

Команда Liberty :dev запускает сервер Open Liberty в режиме разработки , который выполняет горячую перезагрузку любых изменений, внесенных в код или конфигурацию, без перезапуска сервера.

Точно так же доступна команда Liberty:Run для запуска сервера в производственном режиме.

Кроме того, мы можем использовать Liberty:Start-Server и Liberty: Stop-Server для запуска/остановки сервера в фоновом режиме . ``

4. Сервлет

Чтобы использовать сервлеты в приложении, мы добавим функцию servlet-4.0 в server.xml :

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

Добавьте последнюю зависимость Maven servlet-4.0 , если используете зависимость Maven openliberty-runtime в pom.xml :

<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 , расширяющий класс 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);
}
}

Здесь мы добавили аннотацию @WebServlet , которая сделает AppServlet доступным по указанному шаблону URL.

Давайте получим доступ к сервлету по адресу localhost:9080/app :

**

./f7c8a9a7da787b0f1b04701f48b99a3f.png

**

5. Создайте веб-службу RESTful

Во-первых, давайте добавим функцию jaxrs-2.1 в server.xml :

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

Затем мы создадим класс ApiApplication , который предоставляет конечные точки для веб-службы RESTful:

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

Здесь мы использовали аннотацию @ApplicationPath для пути URL.

Затем давайте создадим класс Person , обслуживающий модель:

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

// getters and setters
// 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/persons . Итак, веб-служба RESTful готова, и команда Liberty:dev будет загружать изменения «на лету».

Давайте получим доступ к веб-службе /api/persons RESTful с помощью запроса curl GET:

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

Затем мы получим в ответ массив JSON:

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

Точно так же мы можем добавить сопоставление POST, создав метод addPerson :

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

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.

Во-первых, мы добавим зависимость 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 предоставляет Java API для обработки JSON, а функция cdi-2.0 обрабатывает области действия и внедрение зависимостей.

Далее мы создадим файл persistence.xml в каталоге src/main/resources/META-INF :

<?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 для автоматического создания нашей схемы базы данных. Мы также можем использовать другие альтернативы, такие как Hibernate.

Затем добавим конфигурацию источника данных в 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 имеет ту же ссылку на тег jta-data-source в файле persistence.xml.

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
}

Далее создадим класс 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);
}
}

Обратите внимание, что @PersistenceContext определяет ту же ссылку на тег persistence-unit в файле persistence.xml .

Теперь мы добавим зависимость PersonDao в класс PersonResource :

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

// ...
}

Здесь мы использовали аннотацию @Inject , предоставляемую функцией CDI.

Наконец, мы обновим метод addPerson класса PersonResource , чтобы сохранить объект 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.

Давайте вызовем конечную точку уже обсуждавшимся POST-запросом curl:

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.

Точно так же давайте добавим метод getPerson с отображением GET для получения объекта 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. Использование веб-службы RESTful с использованием JSON-B

Во-первых, мы включим возможность прямой сериализации и десериализации моделей, добавив функцию jsonb-1.0 в server.xml :

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

Затем создадим класс RestConsumer с методом потребленияWithJsonb :

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.

Наконец, давайте напишем модульный тест для использования веб-службы /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());
}

Здесь мы использовали класс JsonbBuilder для анализа ответа String в объекте Person .

Кроме того, мы можем использовать MicroProfile Rest Client, добавив функцию mpRestClient-1.3 для использования веб-служб RESTful . Он предоставляет интерфейс RestClientBuilder для запроса конечных точек веб-службы RESTful.

8. Заключение

В этой статье мы рассмотрели платформу Open Liberty — быструю и легкую среду выполнения Java, которая предоставляет все функции платформ Eclipse MicroProfile и Jakarta EE.

Для начала мы создали веб-службу RESTful с использованием JAX-RS. Затем мы включили постоянство, используя такие функции, как JPA и CDI.

Наконец, мы использовали веб-службу RESTful с использованием JSON-B.

Как обычно, все реализации кода доступны на GitHub .