Camada de Integração
Introdução
A integração entre microsserviços ocorre via API (Application Programming Interface).
Nesse contexto, a presente arquitetura oferece duas maneiras principais para implementação de integração. São elas:
-
Via webservices: Na qual as aplicações, então clientes, consomem webservices de outras aplicações. A integração por webservices oferece algumas vantagens, como:
-
Simplicidade de implementação, pois as classes que consomem webservices, aqui chamadas de “Remotes”, são quase que triviais.
-
Monitoramento e análise de tráfego facilitados, em razão de o protocolo HTTP ser amigável às tecnologias de observabilidade, tal como tracing distribuído.
-
-
Via broker de mensageria, como AMQP: Através da construção de tópicos de distribuição de mensagens. Esse modelo é preferido quando há necessidade de:
-
Roteamento avançado de requisições, onde, por exemplo, um comando precisa ser entregue a vários microsserviços de destino; e/ou
-
Maior performance; e/ou
-
Tolerância a interrupções na comunicação ou indisponibilidade de microsserviço, pois o broker tem capacidade de persistir as mensagens e entregá-as aos destinatários quando eles se recuperarem.
-
Outras formas de integração poderão ser implementadas a depender de requisitos técnicos específicos. Um microsserviço não deve acessar diretamente o banco de dados de outro microsserviço, salvo em cenários especiais.
Estrutura de Pacotes
A camada de integração tem a seguinte estrutura de pacotes:
Pacote | Descrição |
---|---|
.remotes.nomeMicrosservicoRemoto.nomeFuncionalidade | Contém as classes clientes para comunicação com outros microsserviços ou serviços externos. |
Estereótipos de Classes
As classes de serviço que fazem a implementação do lado cliente de um endpoint webservice são
chamadas de “Remotes”. A arquitetura oferece o estereótipo @Remote
para essa finalidade.
A seguir são definidas as diretrizes para classes de serviços remotos.
@Remote
-
Herdam de
BaseRemote
e são anotadas com@Remote
. -
Têm sufixo
Remote
. -
São singletons e stateless, não devendo manter estados em seus atributos.
-
Consomem somente 1 (um) endpoint remoto.
-
São localizadas no pacote
.remotes.{nomeMicrosservicoRemovo}.{nomeFuncionalidade}
de acordo com o caminho do endpoint. -
Recebem e retornam dados na forma de DTOs, localizados no mesmo pacote da classe Remote.
-
Têm nome igual ao da operação do endpoint.
-
Utilizam preferencialmente
WebClientComponent
doCloudsupport
para fazer a comunicação webservice, apresentado a seguir.
Exemplo:
@Remote
public class EnviarNotificacaoRemote extends BaseRemote() {
@Inject WebClientComponent component;
public EnviarNotificacaoRetorno enviarNotificacao(EnviarNotificacaoParams params) {
return component
.authenticatedPost("/notificacoes/enviarNotificacao.v1")
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(params)
.retrieve()
.bodyToMono(EnviarNotificacaoRetorno.class)
.timeout(Duration.ofSeconds(5))
.block();
}
}
No exemplo, o serviço remoto é o “enviarNotificacao”, na sua versão “v1”, disponibilizado pelo microsserviço “notificacoes”.
WebClientComponent
O componente WebClientComponent
é recomendado para consumo de webservices e oferece os seguintes
recursos:
-
Utiliza internamente singleton do
WebClient
do SpringBoot, portanto compatível com pilhas Servlet e Reactive, com suporte nativo a pool de conexões e requisições não bloqueantes, visando maior performance. -
Faz a resolução da URL do endpoint a partir de propriedades do profile, permitindo que o código-fonte se adapte conforme o ambiente, por exemplo, local, homologação ou produção.
-
Fornece os métodos que propagam o Access Token OAuth2 (ex: JWT) do contexto do Spring Security, bem como os cabeçalhos “X-Forwarded-For” e “X-Forwarded-Proto”, sendo úteis para consumo de webservices dos demais microsserviços da aplicação, tal que a autenticação do usuário é mantida ao longo do fluxo distribuído de requisições webservices.
O WebClient utilizado pelo componente é construído sobre o WebClient padrão da aplicação, o que permite a incorporação de incrementos, como balanceadores de carga e monitoramento.
Resolução de Rota
A configuração do apontamento do serviço remoto é realizada nas propriedades de profile com prefixo
cloudsupport.remotes.route
. É possível configurar em nível de microsserviço, ou por operação
específica, conforme a seguir.
Configurando o apontamento de uma operação específica:
cloudsupport.remotes.route.notificacoes.enviarNotificacao=https://dominio:porta
Configurando o apontamento de todas as operações de um microsserviço:
cloudsupport.remotes.route.notificacoes=https://dominio:porta
Os arquivos de profile ficam na pasta resources
da aplicação, separados por ambiente:
application-<ambiente>.properties
ou application-<ambiente>.yml
.
Operações
As operações disponíveis no componente são:
Método | Descrição |
---|---|
authenticatedGet(endpoint) | Prepara uma requisição HTTP GET “autenticada” para o endpoint informado, com resolução de URL baseada no profile, propagação de Bearer Token (ex: JWT) e propagação dos cabeçalhos “X-Forwarded-For” e “X-Forwarded-Proto”. Para uso entre microsserviços confiáveis, tipicamente aqueles que compõem o mesmo sistema. Retorna o tipo de objeto do método uri() do WebClient do SpringBoot. |
authenticatedPost(endpoint) | Prepara uma requisição HTTP POST “autenticada” para o endpoint informado, com as mesmas funcionalidades do authenticatedGet . |
get(endpoint) | Prepara uma requisição HTTP GET para o endpoint informado, com resolução de URL baseada no profile, porém sem propagação de Bearer Token (ex: JWT) ou dos cabeçalhos “X-Forwarded-For” e “X-Forwarded-Proto”. Para uso no consumo de serviços externos à aplicação, em que não se deseja propagar dados de autenticação do usuário. Retorna o tipo de objeto do método uri() do WebClient do SpringBoot. |
post(endpoint) | Prepara uma requisição HTTP POST para o endpoint informado, com as mesmas funcionalidades do get . |
defaultClient() | Retorna o WebClient interno, singleton, utilizado nas operações get() e post() do componente. Pode ser utilizado para modificar (mutate) o WebClient e adicionar recursos, como filtros. |
authenticated() | Retorna o WebClient interno, singleton, utilizado nas operações authenticatedGet() e authenticatedPost() do componente. Pode ser utilizado para modificar (mutate) o WebClient e adicionar recursos, como filtros. |
Estendendo o WebClient
Modificar (mutate) o WebClient utilizado pelo WebClientComponent
para adicionar recursos, como filtros, ou configurações.
O exemplo abaixo demonstra a modificação do WebClient para suportar requisições maiores que 256KB:
@Inject WebClientComponent component;
private WebClient withMemory(int mb) {
component
.defaultClient()
.mutate()
.codecs(codecs -> codecs
.defaultCodecs()
.maxInMemorySize(mb * 1024 * 1024))
.build();
}
Neste caso, ao utilizar o WebClient estendido, a resolução de URL de endpoint pode ser assim implementada:
@Inject RemoteRouteResolver routeResolver;
// ...
withMemory(2)
.get()
.uri(routeResolver.getRoute("/notificacoes/enviarNotificacao.v1"))
// ...
Próximos Passos
A próxima leitura sugerida é a seção Segurança, que detalha a utilização do padrão OpenID Connect.