Совсем недавно вышла новая версия MicroProfile - 4.1. Я бы хотел рассказать, что вообще такое MicroProfile, для чего он применяется, из каких компонентов состоит и чем привлекает к себе разработчиков. В этой статье я покажу несколько примеров того, как он может использоваться на практике на примере работы с Quarkus, фреймворком, который является одной из множества реализаций спецификаций MicroProfile.
Что такое MicroProfile?
Так что же это всё-таки такое и какие проблемы на самом деле решает? Некторое время назад глядя на медленное развитие Java EE, несколько лидеров отрасли собрались вместе, чтобы обсудить дальнейшие пути развития этой технологии в сфере энтерпрайз разработки. 14 июня 2016 года IBM, Red Hat, Payara, LJC, Tomitribe и другие независимые компании основали сообщество MicroProfile и зарегистрировали домен https://microprofile.io. 27 июня 2016 года на презентации DevNation в Сан-Франциско, Калифорния, было официально объявлено о создании MicroProfile.
В экосистеме Java уже существует множество «микросервисных» платформ, фреймворков и решений из мира энтерпрайз. Эти проекты предоставляют возможности для работы с микросервисными архитектурами с использованием Jakarta EE / Java EE и других технологий. Целью проекта MicroProfile является создание новых общих API и специфкаций функций, которые будут приняты сообществом. Также одной из целей является скорость развитие этих общих API и специфкаций в ногу с современными подходами к разработке микросервисных приложений. MicroProfile в основном предоставляет согласованную спецификацию API, которой может следовать любой проект, реализовать её и продвигать на рынке.
По сути, MicroProfile это просто набор спецификаций для создания микросервисов. В данный момент он включает в себя 13 спецификаций
Реализации
В настоящее время существуют следующие реализации MicroProfile от разных поставщиков:
Кто-то может спросить, почему, например, здесь не был упомянут Micronaut? Micronaut также поддерживает шаблоны Retry, Fallback и Circuit Breaker, но больше полагается на реализации аспектно-ориентированного программирования и избегает использования механизма рефлексии для решения своих задач, а также Micronaut использует собственные подходы, вдохновленные другими фреймворками, такими как Spring.
Eclipse MicroProfile Starter
Каждая версия MicroProfile предлагает набор спецификаций и реализуется несколькими вендоами. Различные спецификации могут быть созданы с помощью так называемого стартера MicroProfile - https://start.microprofile.io. MicroProfile Starter помогает разработчикам начать процесс разработки микросервисов, выбирая наиболее удобную реализацию из списка доступных для выбранной версии MicroProfile. Это означает, что вы можете выбрать реализацию от любого вендора и посмотреть, какая версия, совместимая с MicroProfile, доступна вместе со спецификациями, которые вы хотите использовать для своего приложения. Для примера на изображении ниже я выбрал несколько, чтобы продемонстрировать, что будет предоставлено для различных спецификаций. Все они выбраны с Quarkus как конкретной реализацией поставщика.
Далее я рассмотрю некоторые из специйикаций MicroProfile.
Microprofile Fault Tolerance
https://github.com/eclipse/microprofile-fault-tolerance
Для обеспечения отказоустойчивости ваших сервисов Microprofile предоставляет спецификацию Microprofile Fault Tolerance, которая предоставляет такие возможности как @Retry, @Timeout, @Fallback и @CircuitBreaker. Существует множество вариантов для конфигурации отказоустойчивости сервиса и того, как это всё может быть применено. Ниже приведён небольшой пример кода:
package com.dvddhln.demo.microprofile.with.quarkus.resilient;
import org.eclipse.microprofile.faulttolerance.Fallback;
import org.eclipse.microprofile.faulttolerance.Timeout;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("/resilience")
@ApplicationScoped
public class ResilienceController {
@Fallback(fallbackMethod = "fallback") // better use FallbackHandler
@Timeout(500)
@GET
public String checkTimeout() {
try {
Thread.sleep(700L);
} catch (InterruptedException e) {
//
}
return "Never from normal processing";
}
public String fallback() {
return "Fallback answer due to timeout";
}
}
Microprofile Metrics
https://github.com/eclipse/microprofile-metrics
Эта спецификация создана для унифицированного способа предоставления различных телеметрических данных сервисами на базе Microprofile. Microprofile Metrics предоставляет способ регистрации метрик, специфичных для приложения, которые впоследствии могут быть отправлены, например, в Promethus. Ниже приведён небольшой пример использования:
package com.dvddhln.demo.microprofile.with.quarkus.metric;
import org.eclipse.microprofile.metrics.Counter;
import org.eclipse.microprofile.metrics.MetricUnits;
import org.eclipse.microprofile.metrics.annotation.Gauge;
import org.eclipse.microprofile.metrics.annotation.Metric;
import org.eclipse.microprofile.metrics.annotation.Timed;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.Random;
@Path("/metric")
@ApplicationScoped //Required for @Gauge
public class MetricController {
@Inject
@Metric(name = "endpoint_counter")
// https://quarkus.io/guides/cdi-reference#private-members
// - private Counter counter;
Counter counter;
@Path("timed")
@Timed(name = "timed-request")
@GET
public String timedRequest() {
// Demo, not production style
int wait = new Random().nextInt(1000);
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
// Demo
e.printStackTrace();
}
return "Request is used in statistics, check with the Metrics call.";
}
@Path("increment")
@GET
public long doIncrement() {
counter.inc();
return counter.getCount();
}
@Gauge(name = "counter_gauge", unit = MetricUnits.NONE)
private long getCustomerCount() {
return counter.getCount();
}
}
Microprofile Open API
https://github.com/eclipse/microprofile-open-api
Эта спецификация MicroProfile нацелена на предоставление унифицированного Java API для документирования ваших сервисов по спецификации OpenAPI v3. Вот небольшой пример использования этого:
package com.dvddhln.demo.microprofile.with.quarkus.openapi;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.info.Info;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@Path("/booking")
@ApplicationScoped
@OpenAPIDefinition(info = @Info(title = "Booking endpoint", version = "1.0"))
public class BookingController {
@APIResponses(value = {
@APIResponse(
responseCode = "200",
description = "Booking for id",
content = @Content(
mediaType = MediaType.APPLICATION_JSON,
schema = @Schema(ref = "Booking"))
),
@APIResponse(
responseCode = "404",
description = "No booking found for the id.")
})
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("{bookingId}")
public Response getBooking(@PathParam("bookingId") String bookingId) {
return Response
.status(Response.Status.OK)
.entity(Booking.booking(bookingId, Destination.destination("New Rearendia", "Wheeli")))
.build();
}
}
Microprofile Health
https://github.com/eclipse/microprofile-health
Эта спецификация предоставляет возможность проверки работоспособности и исправности вашего сервиса. Для этого используется две аннотации:
для проверки готовности сервиса используется аннотация @Readiness;
для проверки того, что сервис жив, используется аннотация @Liveness.
package com.dvddhln.demo.microprofile.with.quarkus.health;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
import javax.enterprise.context.ApplicationScoped;
@Liveness
@ApplicationScoped
public class ServiceLiveHealthCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
return HealthCheckResponse.named(ServiceLiveHealthCheck.class.getSimpleName())
.withData("live", true)
.up()
.build();
}
}
Стоит отметать, что компоненты проверки работоспособности сервиса являются компонентами CDI, поэтому их также можно определить с помощью CDI продюсеров. Таким образом, приведенный выше пример может выглядеть примерно так:
@ApplicationScoped
class MyChecks {
@Produces
@Liveness
HealthCheck check1() {
return () -> HealthCheckResponse.named("heap-memory").status(getMemUsage() < 0.9).build();
}
@Produces
@Readiness
HealthCheck check2() {
return () -> HealthCheckResponse.named("cpu-usage").status(getCpuUsage() < 0.9).build();
}
@Produces
@Startup
HealthCheck check3() {
return () -> HealthCheckResponse.named("initial-heap-memory").status(getMemUsage() < 0.95).build();
}
}
Для самой простой проверки работоспособности и готовности сервиса обе проверки могут помечать один и тот же класс:
@ApplicationScoped
@Liveness
@Readiness
public class MyCheck implements HealthCheck {
public HealthCheckResponse call() {
[...]
}
}
Microprofile Rest Client
https://github.com/eclipse/microprofile-rest-client
REST клиент MicroProfile обеспечивает типобезопасный подход для вызова RESTful сервисов через HTTP. Насколько это возможно, клиент пытается использовать Jakarta RESTful Web Services 2.1 для обеспечения согласованности и упрощения повторного использования. Вот небольшой пример:
package com.dvddhln.demo.microprofile.with.quarkus.client;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@RegisterRestClient
@ApplicationScoped
public interface Service {
@GET
@Path("/{parameter}")
String doSomething(@PathParam("parameter") String parameter);
}
Microprofile Config
https://github.com/eclipse/microprofile-config
MicroProfile Config использует внедрение контекстов и зависимостей (CDI) для внедрения значений свойств конфигурации непосредственно в приложение не требуя написания дополнительного пользовательского кода для их извлечения. Значения конфигурации определяются как статические, поскольку они устанавливаются только при запуске приложения. Microprofile Config позволяет объединяет значения конфигурации из нескольких источников, каждый из которых объявлен как ConfigSource. Каждый ConfigSource имеет определенный приоритет, определяемый его порядковым номером. Более высокий порядковый номер означает, что значения, взятые из этого ConfigSource, переопределят значения из ConfigSources с более низким порядковым номером. Ниже приведён небольшой пример использования Microprofile Config:
package com.dvddhln.demo.microprofile.with.quarkus.config;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
@Path("/config")
@RequestScoped
public class ConfigTestController {
@Inject
@ConfigProperty(name = "injected.value")
// https://quarkus.io/guides/cdi-reference#private-members
// - private String injectedValue;
String injectedValue;
@Path("/injected")
@GET
public String getInjectedConfigValue() {
return "Config value as Injected by CDI " + injectedValue;
}
@Path("/lookup")
@GET
public String getLookupConfigValue() {
Config config = ConfigProvider.getConfig();
String value = config.getValue("value", String.class);
return "Config value from ConfigProvider " + value;
}
}
Заключение
В этой статье были обзорно рассмотрены некоторые из спецификаций, которые предоставляются Microprofile. Если вам интересна эта тема а также тема реализаций этих спецификаций, я приглашаю вас присоединяться к моему телеграм-каналу о Quarkus, где можно найти дополнительную информацию по этой теме и конечно же узнать гораздо больше о Quarkus как одной из реализаций Microprofile.
boiarshinov
Подскажите, пожалуйста, зачем Microprofile написали свою собственную реализацию OpenApi, если есть уже готовая библиотека от мейнтейнеров OpenApi - SmartBear?
gleb_the_human Автор
Microprofile это просто набор спецификаций без реализаций, в контесте OpenApi - Microprofile определяет Java API для работы с OpenApi. А вот Swagger это уже реализация конкетных инструментов для работы с OpenApi.
Подробнее можно почитать в этой статье.