The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Continuum

Por anos, a arquitetura cliente-servidor tem sido o padrão de fato para criar aplicativos. Mas uma mudança significativa aconteceu. A era do único modelo que rege todos eles acabou. Uma nova gama de aplicativos e estilos de arquitetura surgiram e transformaram a forma como o código é escrito e como as aplicações são implantadas e executadas. Microsserviços HTTP, aplicações reativas, arquitetura orientada a eventos e sem servidor agora são atores centrais em sistemas modernos.

O Quarkus foi projetado com esse novo mundo em mente e fornece suporte de primeira classe para esses diferentes paradigmas. Isso não significa que você não possa construir monólitos com Quarkus; você pode fazê-lo sem problemas. Pelo contrário, isso significa que o modelo de desenvolvimento do Quarkus se transforma para se adaptar ao tipo de aplicação que você está desenvolvendo, monólito, microsserviço, reativo, orientado a eventos, funções...

Microsserviços HTTP

Vamos começar com o básico: microsserviços HTTP. Nesse contexto, você precisa desenvolver um endpoint HTTP, geralmente chamado de REST ou CRUD. Você processa solicitações HTTP de entrada e, para isso, geralmente precisa confiar em outros serviços, como bancos de dados ou outro serviço HTTP.

Para esse tipo de aplicação, o Quarkus conta com padrões bem conhecidos, como JAX-RS, JPA e MicroProfile Rest Client, mas também Hibernate com Panache para simplificar as interações com bancos de dados.

Vamos pegar uma aplicação muito simples manipulando elementos da tabela periódica. O código seria algo como:

@Path("/elements")
        public class ElementResource {

    @GET
    public List<Element> getAll() {
        return Element.listAll();
    }

    @GET
    @Path("/{position}")
    public Element getOne(@PathParam("position") int position) {
        Element element = Element.find("position", position).firstResult();
        if (element == null) {
            throw new WebApplicationException("Element with position " + position + " does not exist.", 404);
        }
        return element;
    }

    @POST
    @Transactional
    public Response create(Element element) {
        element.persist();
        return Response.ok(element).status(201).build();
    }

    //...
}

Se você é um usuário Java EE ou Spring, esse modelo de desenvolvimento deve parecer familiar. Você expõe um recurso que contém métodos anotados com @GET, @POST... para lidar com as diferentes solicitações. O caminho é especificado usando a @Path anotação. O Quarkus também oferece suporte a anotações do controlador Spring , como @GetMapping ou @RestController.

Você pode usar o gerenciador de entidade JPA diretamente. Panache propõe uma alternativa removendo clichês e expondo uma solução active record e também modelado como um repositório.

Com o Panache, a classe Element seria tão simples quanto:

@Entity
public class Element extends PanacheEntity {

    public String name;
    public String symbol;
    @Column(unique = true)
    public int position;
}

Os microsserviços tendem a vir em sistemas. Agora vamos imaginar que você precise acessar outro endpoint HTTP. Você pode usar um cliente HTTP diretamente; isso nada mais é do que repetir código clichê. O Quarkus fornece uma maneira de chamar endpoints HTTP facilmente usando a MicroProfile Rest Client API.

Primeiro declare seu serviço da seguinte maneira:

@Path("/elements")
@RegisterRestClient(configKey="element-service")
public interface ElementService {

    @GET
    @Path("/{position}")
    Element getElement(@PathParam("position") int position);
}

Para cada chamada que você pretende fazer, adicione um método e use anotações para descrever o comportamento. Você pode combinar o cliente REST com a extensão de tolerância a falhas para lidar com falhas normalmente. Depois, no seu recurso, basta utilizar a ElementService interface:

@Path("/elem")
public class ElementResource {

    @RestClient
    ElementService elements;

    @GET
    @Path("/{position}")
    public Element name(@PathParam("position") int position) {
        return elements.getElement(position);
    }
}

Mas você pode estar se perguntando onde a URL está configurada, pois não está no código. Lembre-se, ele não deve ser embutido em código porque a URL provavelmente depende do ambiente. A URL é configurada na configuração do aplicativo:

element-service/mp-rest/url=http://localhost:9001

A URL agora pode ser atualizada durante a implantação ou no momento da inicialização usando propriedades do sistema ou variáveis de ambiente.

O Quarkus não está limitado a HTTP. Você pode usar gRPC ou GraphQL, duas alternativas proeminentes no espaço de microsserviços.

Sendo reativo

Os requisitos das aplicações mudaram drasticamente nos últimos anos. Para que qualquer aplicação tenha sucesso na era da computação em nuvem, Big Data ou IoT, tornar-se reativo está se tornando cada vez mais o estilo de arquitetura a ser seguido.

Os usuários de hoje adotam aplicações com milissegundos de tempo de resposta, disponibilidade de 100%, menor latência, dados por push em vez de pull, maior taxa de transferência e elasticidade. No entanto, esses recursos são quase impossíveis de alcançar usando a arquitetura de software de ontem sem um investimento considerável em recursos, infraestrutura e ferramentas. O mundo mudou, e ter dezenas de servidores, longos tempos de resposta (> de 500 ms), tempo de inatividade devido a manutenção ou cascatas de falhas não atende à experiência esperada do usuário.

Quarkus ajuda você em sua jornada para reativo. O Quarkus é baseado em um núcleo reativo , permitindo que sua aplicação misture componentes reativos e imperativos. Como exemplo, você pode implementar o endpoint HTTP reativo usando a extensão RESTEasy Reactive da seguinte maneira:

@GET
@Path("/elements/{position}")
public Uni<Element> getElement(@PathParam("position") int position) {
    return elements.getElement(position)
        .onFailure().recoverWithItem(FALLBACK);
}

Graças à Mutiny Reactive API , você pode compor operações assíncronas e concluir o resultado quando tudo for feito sem bloquear os threads de E/S. Isso melhora muito o consumo de recursos e a elasticidade. A maioria das APIs do Quarkus está disponível em imperativa e reativa. Como exemplo, você pode usar a versão reativa do cliente REST:

@Path("/elements")
@RegisterRestClient(configKey="element-service")
public interface ElementService {

    @GET
    @Path("/{position}")
    Uni<Element> getElement(@PathParam("position") int position);
}

Mas, e os streamings? Gerar uma resposta server-sent event com o Quarkus é igualmente simples:

@Produces(MediaType.SERVER_SENT_EVENTS)
@GET
@Path("/events")
public Multi<String> stream() {
    return kafka.toMulti();
}

Arquiteturas orientadas a eventos

No entanto, as características HTTP proíbem a implementação de sistemas reativos, onde todos os componentes interagem usando a passagem assíncrona de mensagens.

Primeiro, você pode consumir mensagens de vários brokers, como AMQP ou Apache Kafka, e processar essas mensagens sem problemas:

@ApplicationScoped
public class MyEventProcessor {

  @Incoming("health")
  @Outgoing("heartbeat")
  public double extractHeartbeat(Health health) {
    return health.getHeartbeat();
  }
}

As anotações@Incoming e @Outgoing fazem parte do Reactive Messaging. Eles são usados para expressar de qual channel você está consumindo e para qual channel você está enviando. Graças ao Reactive Messaging, você pode consumir e enviar mensagens de e para diferentes brokers e transportes, como HTTP, Kafka ou Apache Camel.

Às vezes, você precisa de mais do que apenas lidar com mensagens uma a uma. Você também pode expressar sua lógica de processamento de mensagens usando programação reativa, conforme ilustrado no trecho a seguir:

@Incoming("health")
@Outgoing("output")
public Multi<Record<String, Measure> filterState(Multi<Capture> input) {
    return input
        .drop().repetitions()
        .select().where(capture -> capture.value > 0)
        .onItem().transform(capture -> new Measure(capture.sensor, capture.value, capture.unit))
        .onItem().transform(measure -> Record.of(measure.sensor, measure));
}

Quanto às APIs reativas expostas pelo Quarkus, a manipulação de fluxo usa a API Mutiny .

Functions as a Service and Serverless

Graças ao seu excelente tempo de inicialização e baixo uso de memória, você pode implementar funções usando o Quarkus para serem usadas em ambientes sem servidor. O Quarkus fornece o Funqy, uma abordagem para escrever funções que podem ser implantadas em vários ambientes FaaS, como AWS Lambda, Azure Functions, Knative, e Knative Events (Cloud Events). Também é utilizável como um serviço independente.

Com o Funqy, uma função é apenas:

import io.quarkus.funqy.Funq;

public class GreetingFunction {
    @Funq
    public String greet(String name) {
       return "Hello " + name;
    }
}

Você pode usar qualquer um dos recursos do Quarkus em sua função e se beneficiar da inicialização rápida e da baixa utilização de memória. Com o Quarkus, você pode abraçar esse novo mundo sem ter que mudar sua linguagem de programação.