Especialização em Backend com Java & Spring Boot • Spring Boot 3 & Java 21 LTS • Spring Data JPA, Security, Microsserviços e Cloud


🗺️ Mapa Conceitual do Tópico

flowchart TD
    A["Cliente HTTP / Frontend"] --> B["API Gateway / Router"]
    B --> C["Controller / Handler"]
    C --> D["Service Layer (Regras de Negócio)"]
    D --> E["Repository / ORM (Persistência)"]
    E --> F["Banco de Dados / Cache"]

    subgraph ARQ["Arquitetura do Capítulo"]
        G["Conceito: Arquitetura de Microsserviços com Spring Cloud e Gateway"]
        H["Segurança, Validação e Resiliência"]
        I["Alta Performance e Escalabilidade"]
    end

    D --> ARQ

    style A fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
    style B fill:#fff3e0,stroke:#ff9800,stroke-width:2px
    style C fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
    style D fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
    style E fill:#fce4ec,stroke:#e91e63,stroke-width:2px
    style F fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px

🏛️ 1. Fundamentos Técnicos de Arquitetura de Microsserviços com Spring Cloud e Gateway

O problema que a arquitetura de microsserviços resolve — e o que ela custa. Decompor um monólito em serviços independentes permite deploy, escala e times autônomos por domínio de negócio, mas troca a complexidade de código (dentro de um processo) por complexidade de rede (entre processos): endereços IP mudam a cada deploy/escala, chamadas de rede falham de formas que chamadas de método nunca falham, e não existe mais uma transação de banco única cobrindo múltiplos serviços. O Spring Cloud é a coleção de ferramentas que endereça exatamente essa complexidade distribuída — descoberta de serviços, roteamento de borda e configuração centralizada.

Service Discovery: eliminar IPs hardcoded. Em um cluster onde instâncias sobem e descem dinamicamente (escala automática, rolling deploys, falhas), fixar o endereço de outro serviço no código ou em configuração estática é inviável. Um Service Registry (Eureka, Consul) funciona como um catálogo dinâmico: cada instância se registra ao subir (@EnableDiscoveryClient) e envia heartbeats periódicos confirmando que está viva; instâncias que param de enviar heartbeat são removidas do catálogo automaticamente. Outros serviços consultam esse catálogo por nome lógico (cliente-service) em vez de IP, e o cliente HTTP resolve esse nome para uma instância saudável em tempo real.

Comunicação declarativa com OpenFeign. Escrever um cliente HTTP manualmente (montar URL, serializar corpo, tratar códigos de erro) para cada chamada entre serviços é repetitivo e propenso a erro. @FeignClient(name = "cliente-service") gera a implementação do cliente HTTP em tempo de execução a partir de uma interface Java declarativa — o desenvolvedor apenas declara a assinatura do endpoint (@GetMapping("/api/v1/clientes/{id}")) como se fosse um método local, e o Feign resolve a URL via Service Discovery, aplica balanceamento de carga (Spring Cloud LoadBalancer) entre as instâncias disponíveis, e desserializa a resposta automaticamente.

Spring Cloud Gateway: o ponto único de entrada. Expor cada microsserviço diretamente à internet obrigaria replicar autenticação, rate limiting e CORS em todos eles. O Gateway atua como reverse proxy reativo (construído sobre WebFlux/Netty, não-bloqueante) na borda do sistema: rotas declarativas mapeiam padrões de path (/pedidos/**) para serviços internos usando o prefixo lb:// (load-balanced, resolvido via Service Discovery), e filtros compõem comportamento transversal — reescrita de URL, injeção de cabeçalhos, validação de JWT, circuit breaking — sem que cada serviço interno precise reimplementar essa lógica.

Configuração centralizada com Spring Cloud Config e @RefreshScope. Gerenciar arquivos application.yml espalhados por dezenas de serviços, cada um exigindo redeploy para mudar uma propriedade, não escala operacionalmente. O Config Server centraliza a configuração em um repositório Git versionado, servido via HTTP para os clientes na inicialização. @RefreshScope em um bean permite ir além: republicar um evento de /actuator/refresh recarrega o valor de @Value sem reiniciar a aplicação, útil para ajustar parâmetros de negócio (taxas, feature flags) em produção sem janela de deploy.

O trade-off central: latência de rede e falhas parciais. Cada chamada entre serviços que antes era uma chamada de método (nanosegundos, sempre bem-sucedida) vira uma chamada de rede (milissegundos, pode falhar, pode expirar, pode duplicar). Essa é exatamente a motivação para os padrões de resiliência (circuit breaker, retry, timeout) tratados no próximo capítulo — a arquitetura distribuída não é “grátis”: ela troca simplicidade de execução por flexibilidade operacional, e exige tratamento explícito de falha parcial que um monólito nunca precisou considerar.


💻 2. Código de Demonstração Corporativo

package com.empresa.api.gateway;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class GatewayRoutesConfig {

    @Bean
    public RouteLocator customRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
            // "lb://" resolve o nome lógico via Service Discovery e balanceia entre instâncias.
            .route("pedidos_route", r -> r.path("/pedidos/**")
                .filters(f -> f.stripPrefix(1).addRequestHeader("X-Gateway-Origin", "edge"))
                .uri("lb://pedidos-service"))
            .route("pagamentos_route", r -> r.path("/pagamentos/**")
                .filters(f -> f.circuitBreaker(c -> c.setName("pagamentosCB")
                    .setFallbackUri("forward:/fallback/pagamentos")))
                .uri("lb://pagamentos-service"))
            .build();
    }
}
package com.empresa.api.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// "cliente-service" é resolvido via Service Discovery: sem IP/porta hardcoded.
@FeignClient(name = "cliente-service")
public interface ClienteFeignClient {

    @GetMapping("/api/v1/clientes/{id}")
    ClienteDTO buscarClientePorId(@PathVariable("id") Long id);
}

🔗 Recursos Pedagógicos do Capítulo 17

Recurso Didático Finalidade Link de Acesso
📊 Slides de Aula Apresentação visual interativa com Dark Mode e suporte a teclado Ver Slides
🧠 Quiz Formativo Teste interativo de fixação com feedback imediato por alternativa Fazer Quiz
💻 Exemplos de Código Demonstrações funcionais com código executável Ver Exemplos
🧩 Exercícios em 4 Níveis Lista progressiva de fixação com gabarito em bloco colapsável Resolver Exercícios

⬅️ Capítulo Anterior 📚 Sumário de Tópicos Próximo Capítulo ➡️