Построение микросервисов с Eclipse MicroProfile

Создание микросервисов с Eclipse MicroProfile

1. обзор

В этой статье мы сосредоточимся на создании микросервиса на основе Eclipse MicroProfile.

Мы рассмотрим, как написать веб-приложение RESTful с использованием API JAX-RS, CDI и JSON-P.

2. Микросервисная архитектура

Проще говоря, микросервисы - это стиль архитектуры программного обеспечения, который формирует целостную систему как совокупность нескольких независимых сервисов.

Каждый фокусируется на одном функциональном периметре и общается с другими с помощью независимого от языка протокола, такого как REST.

3. Eclipse MicroProfile

Eclipse MicroProfile - это инициатива, направленная на оптимизацию Enterprise Java для архитектуры микросервисов. Он основан на подмножестве API-интерфейсов Java EE WebProfile, поэтому мы можем создавать приложения MicroProfile, как мы создаем приложения Java EE.

Целью MicroProfile является определение стандартных API-интерфейсов для построения микросервисов и доставки переносимых приложений в различные среды MicroProfile.

4. Maven Зависимости

Все зависимости, необходимые для создания приложения Eclipse MicroProfile, обеспечиваются этой зависимостью спецификации (спецификации):


    org.eclipse.microprofile
    microprofile
    1.2
    pom
    provided

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

5. Модель представления

Начнем с создания быстрого класса ресурсов:

public class Book {
    private String id;
    private String name;
    private String author;
    private Integer pages;
    // ...
}

Как мы видим, у этого классаBook нет аннотации.

6. Использование CDI

Проще говоря, CDI - это API, который обеспечивает внедрение зависимостей и управление жизненным циклом. Это упрощает использование корпоративных компонентов в веб-приложениях.

Давайте теперь создадим управляемый bean-компонент CDI как хранилище для представления книги:

@ApplicationScoped
public class BookManager {

    private ConcurrentMap inMemoryStore
      = new ConcurrentHashMap<>();

    public String add(Book book) {
        // ...
    }

    public Book get(String id) {
        // ...
    }

    public List getAll() {
        // ...
    }
}

Мы аннотируем этот класс@ApplicationScoped, потому что нам нужен только один экземпляр, состояние которого используется всеми клиентами. Для этого мы использовалиConcurrentMap как типобезопасное хранилище данных в памяти. Затем мы добавили методы для операцийCRUD.

Теперь наш bean-компонент готов к CDI и может быть вставлен в bean-компонентBookEndpoint using аннотацию@Inject.

7. JAX-RS API

Чтобы создать приложение REST с JAX-RS, нам нужно создать классApplication, аннотированный@ApplicationPath, и ресурс, аннотированный@Path.

7.1. Приложение JAX RS

Приложение JAX-RS идентифицирует базовый URI, под которым мы представляем ресурс в веб-приложении.

Давайте создадим следующее приложение JAX-RS:

@ApplicationPath("/library")
public class LibraryApplication extends Application {
}

В этом примере все классы ресурсов JAX-RS в веб-приложении связаны сLibraryApplication, что делает их по одному и тому же путиlibrary, что является значениемApplicationPath annotation.

Этот аннотированный класс сообщает среде выполнения JAX RS, что он должен автоматически находить ресурсы и выставлять их.

7.2. Конечная точка JAX RS

КлассEndpoint, также называемый классомResource, должен определять один ресурс, хотя многие из тех же типов технически возможны.

Каждый класс Java, аннотированный@Path или имеющий хотя бы один метод, аннотированный@Path or @HttpMethod, является конечной точкой.

Теперь мы создадим конечную точку JAX-RS, которая предоставляет это представление:

@Path("books")
@RequestScoped
public class BookEndpoint {

    @Inject
    private BookManager bookManager;

    @GET
    @Path("{id}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getBook(@PathParam("id") String id) {
        return Response.ok(bookManager.get(id)).build();
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getAllBooks() {
        return Response.ok(bookManager.getAll()).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response add(Book book) {
        String bookId = bookManager.add(book);
        return Response.created(
          UriBuilder.fromResource(this.getClass())
            .path(bookId).build())
            .build();
    }
}

На этом этапе мы можем получить доступ к ресурсуBookEndpoint по пути/library/books в веб-приложении.

7.3. JAX RS Тип носителя JSON

JAX RS поддерживает множество типов мультимедиа для связи с клиентами REST, ноEclipse MicroProfile restricts the use of JSON указывает на использование JSOP-P API. Таким образом, нам нужно аннотировать наши методы с помощью@Consumes(MediaType.APPLICATION_JSON) и @Produces(MediaType.APPLICATION_JSON)..

Аннотация@Consumes ограничивает допустимые форматы - в этом примере принимается только формат данных JSON. Заголовок HTTP-запросаContent-Type должен бытьapplication/json.

Та же идея лежит в основе аннотации@Produces. JAX RS Runtime должен упорядочить ответ в формате JSON. HTTP-заголовок запросаAccept должен бытьapplication/json.

8. JSON-P

JAX RS Runtime поддерживает JSON-P из коробки, поэтому мы можем использоватьJsonObject в качестве входного параметра метода или типа возвращаемого значения.

Но в реальном мире мы часто работаем с классами POJO. Итак, нам нужен способ отображения междуJsonObject и POJO. Вот где вступает в игру поставщик сущностей JAX RS.

Для маршалинга входного потока JSON в POJOBook, то есть для вызова метода ресурса с параметром типаBook,, нам нужно создать классBookMessageBodyReader:

@Provider
@Consumes(MediaType.APPLICATION_JSON)
public class BookMessageBodyReader implements MessageBodyReader {

    @Override
    public boolean isReadable(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType) {

        return type.equals(Book.class);
    }

    @Override
    public Book readFrom(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType,
      MultivaluedMap httpHeaders,
      InputStream entityStream) throws IOException, WebApplicationException {

        return BookMapper.map(entityStream);
    }
}

Мы делаем тот же процесс, чтобы демаршалироватьBook в выходной поток JSON, то есть вызывая метод ресурса с типом возвращаемого значенияBook,, создаваяBookMessageBodyWriter:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class BookMessageBodyWriter
  implements MessageBodyWriter {

    @Override
    public boolean isWriteable(
      Class type, Type genericType,
      Annotation[] annotations,
      MediaType mediaType) {

        return type.equals(Book.class);
    }

    // ...

    @Override
    public void writeTo(
      Book book, Class type,
      Type genericType,
      Annotation[] annotations,
      MediaType mediaType,
      MultivaluedMap httpHeaders,
      OutputStream entityStream) throws IOException, WebApplicationException {

        JsonWriter jsonWriter = Json.createWriter(entityStream);
        JsonObject jsonObject = BookMapper.map(book);
        jsonWriter.writeObject(jsonObject);
        jsonWriter.close();
    }
}

ПосколькуBookMessageBodyReader иBookMessageBodyWriter аннотируются@Provider, они автоматически регистрируются средой выполнения JAX RS.

9. Сборка и запуск приложения

Приложение MicroProfile является переносимым и должно работать в любой совместимой среде выполнения MicroProfile. Мы объясним, как создать и запустить наше приложение вOpen Liberty, но мы можем использовать любой совместимый Eclipse MicroProfile.

Мы настраиваем среду выполнения Open Liberty через файл конфигурацииserver.xml:


    
        jaxrs-2.0
        cdi-1.2
        jsonp-1.0
    
    
    
    

Давайте добавим плагинliberty-maven-plugin в наш pom.xml:



    net.wasdev.wlp.maven.plugins
    liberty-maven-plugin
    2.1.2
    
        
            io.openliberty
            openliberty-runtime
            17.0.0.4
            zip
        
        ${basedir}/src/main/liberty/config/server.xml
        ${package.file}
        ${packaging.type}
        false
        project
        
            /
            ${project.artifactId}-${project.version}.war
            9080
            9443
        
    
    
        
            install-server
            prepare-package
            
                install-server
                create-server
                install-feature
            
        
        
            package-server-with-apps
            package
            
                install-apps
                package-server
            
        
    

Этот плагин настраивается с помощью набора свойств:


    
    library
    ${project.build.directory}/${app.name}-service.jar
    runnable

Приведенная выше цель exec создает исполняемый файл jar, поэтому наше приложение будет независимым микросервисом, который можно будет развертывать и запускать отдельно. Мы также можем развернуть его как образ Docker.

Чтобы создать исполняемый файл jar, выполните следующую команду:

mvn package

И чтобы запустить наш микросервис, мы используем эту команду:

java -jar target/library-service.jar

Это запустит среду выполнения Open Liberty и развернет наш сервис. Мы можем получить доступ к нашей конечной точке и получить все книги по этому адресу:

curl http://localhost:9080/library/books

Результатом является JSON:

[
  {
    "id": "0001-201802",
    "isbn": "1",
    "name": "Building Microservice With Eclipse MicroProfile",
    "author": "example",
    "pages": 420
  }
]

Чтобы получить одну книгу, мы просим этот URL:

curl http://localhost:9080/library/books/0001-201802

И результат JSON:

{
    "id": "0001-201802",
    "isbn": "1",
    "name": "Building Microservice With Eclipse MicroProfile",
    "author": "example",
    "pages": 420
}

Теперь мы добавим новую книгу, взаимодействуя с API:

curl
  -H "Content-Type: application/json"
  -X POST
  -d '{"isbn": "22", "name": "Gradle in Action","author": "example","pages": 420}'
  http://localhost:9080/library/books

Как мы видим, статус ответа - 201, что указывает на то, что книга была успешно создана, аLocation - это URI, по которому мы можем получить к ней доступ:

< HTTP/1.1 201 Created
< Location: http://localhost:9080/library/books/0009-201802

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

В этой статье демонстрируется, как создать простой микросервис на основе Eclipse MicroProfile, обсуждаются JAX RS, JSON-P и CDI.

Код доступенover on Github; это проект на основе Maven, поэтому его должно быть просто импортировать и запускать как есть.