Создание микросервисов с 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, поэтому его должно быть просто импортировать и запускать как есть.