Spring Boot
Do zero aos microsserviços
com Spring Cloud
Ecossistema do Spring

Ecossistema do Spring

Ecossistema do Spring

# PRESENTING CODE
Configuração em XML - Exemplo
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<http auto-config='true'>
<intercept-url pattern="/css/**" filters="none"/>
<intercept-url pattern="/login.jsp*" filters="none"/>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='/login.jsp'/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="bob" password="bobspassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<!-- DEMAIS CONFIGURAÇÕES DOS OUTROS MÓDULOS ... -->
</beans>Ecossistema do Spring

# PRESENTING CODE
Configuração em Java - Exemplo
@Configuration
@EnableWebSecurity
public class MyOAuthClientConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) ->
requests.anyRequest().authenticated()
)
.oauth2Login((login) ->
login.redirectionEndpoint((endpoint) -> endpoint.baseUri("/login/oauth2/callback/*"))
);
return http.build();
}
}Ecossistema do Spring

Ecossistema do Spring

Ecossistema do Spring

Ecossistema do Spring

- Usa Convention-over-Configuration (CoC)
- Integra vários módulos do Spring "automagicamente"
- E facilita o setup e desenvolvimento de projetos
- ... e tem mais!
O Spring Boot...
Executar aplicação


Executar aplicação


"Exemplo" de aplicação
Criamos o projeto do zero?
🤔

"Exemplo" de aplicação
Criamos o projeto do zero?
🤔

Spring Initializr
https://start.spring.io/

compras/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>br.com.alura</groupId>
<artifactId>compras</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>compras</name>
<description>Serviço de compras</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
# PRESENTING CODE
compras/../ComprasApplication.java
package br.com.alura.compras;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ComprasApplication {
public static void main(String[] args) {
SpringApplication.run(ComprasApplication.class, args);
}
}
# PRESENTING CODE
O Spring Boot é mágico!
Mas todo mágico precisa de ajuda em algum momento!
Não tem como ele vai adivinhar as credenciais de conexão!
🤷🏻♂️

O Spring Boot é mágico!
Mas todo mágico precisa de ajuda em algum momento!
Não tem como ele vai adivinhar as credenciais de conexão!
🤷🏻♂️

O Spring Boot é mágico!
Mas todo mágico precisa de ajuda em algum momento!
Não tem como ele adivinhar as credenciais de conexão!
🤷🏻♂️

compras/.../application.properties
spring.datasource.username = mysql-user
spring.datasource.password = mysql-pass
spring.datasource.url =jdbc:mysql://localhost:3306/compras
#### DEMAIS CONFIGURAÇÕES ####
# PRESENTING CODE
O Spring Boot é maravilhoso para escrever uma aplicação. Mas...
E quando a coisa cresce???

"Quando quebramos coisas grandes em pequenos pedaços, nós passamos a complexidade para a interação entre elas."
Michael Feathers, Microservices Util Macro Complexity
Microservices Patterns


Microservice Chassis



Microservice Chassis



Spring Cloud
- Provê ferramentas para desenvolvedores implementarem padrões de sistemas distribuídos
- Funciona em qualquer ambiente (máquina local, servidores tradicionais (bare metal) e ambientes gerenciados (Kubernetes)
- ... vamos "meter a mão na massa"!
Messaging



Messaging



Messaging

Spring Cloud Stream

Spring Cloud Stream

Spring Cloud Stream

compras/.../application.properties
spring.cloud.stream.binders.rabbit.type = rabbit
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.host = 192.168.15.4
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.port = 5672
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.username = rabbit-user
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.password = rabbit-pass
#### BINDINGS DE INPUT E OUTPUT OMITIDOS ####
# PRESENTING CODE

Spring Cloud Stream





Spring Cloud Stream





Spring Cloud Stream





Externalized Configuration



Externalized Configuration



Spring Cloud Config

Spring Cloud Config

Spring Cloud Config

Spring Cloud Config

config-server/.../application.properties
server.port = 8888
spring.application.name = config-server
spring.cloud.config.server.git.uri = https://github.com/organizacao/config-repo.git
#### CONFIGURAÇÕES QUE ESTAVAM DUPLICADAS ###
spring.cloud.stream.binders.rabbit.type = rabbit
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.host = 192.168.15.4
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.port = 5672
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.username = rabbit-user
spring.cloud.stream.binders.rabbit.environment.spring.rabbitmq.password = rabbit-pass
#### VÁRIOS SERVIÇOS TAMBÉM ACESSAM A MESMA BASE MySQL ###
spring.datasource.username = mysql-user
spring.datasource.password = mysql-pass
spring.datasource.url =jdbc:mysql://localhost:3306/compras
#### BINDINGS DE INPUT E OUTPUT OMITIDOS ####
# PRESENTING CODE

compras/.../bootstrap.properties
spring.cloud.config.uri = http://192/168.15.11:8888
spring.application.name = compras
#### DEMAIS CONFIGURAÇÕES OMITIDAS ####
# PRESENTING CODE

Remote Procedure Invocation



Remote Procedure Invocation



Spring Cloud OpenFeign

compras/.../PagamentoRestClient.java
@FeignClient(url = "${pagamento.service.url}", name = "pagamento")
interface PagamentoRestClient {
@RequestMapping(method = RequestMethod.POST, value = "/api/pagamentos", consumes = "application/json")
ConfirmacaoPagamentoDto efetuaCobranca(SolicitacaoPagamentoDto payload);
}
# PRESENTING CODE
config-server/.../compras.properties
#### DEMAIS CONFIGURAÇÕES OMITIDAS ####
pagamento.service.url = http://192.168.15.5:443
# PRESENTING CODE

Spring Cloud OpenFeign



Spring Cloud OpenFeign



Spring Cloud OpenFeign



Spring Cloud OpenFeign

config-server/.../compras.properties
#### DEMAIS CONFIGURAÇÕES OMITIDAS ####
pagamento.service.url = ?????
# PRESENTING CODE

http://192.168.15.5:443 ou http://192.168.15.6:443?
🤷🏻♂️
Service Discovery



Service Discovery



Spring Cloud Netflix Eureka

Spring Cloud Netflix Eureka

compras/.../PagamentoRestClient.java
// @FeignClient(url = "${pagamento.service.url}", name = "pagamento")
@FeignClient("pagamento")
interface PagamentoRestClient {
@RequestMapping(method = RequestMethod.POST, value = "/api/pagamentos", consumes = "application/json")
ConfirmacaoPagamentoDto efetuaCobranca(SolicitacaoPagamentoDto payload);
}
# PRESENTING CODE
Basta usar o nome do serviço para realizar a requisição.
👏🏼
Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"




Cenário "hipotético"

Cenário "hipotético"

Cenário "hipotético"

Circuit Breaker



Circuit Breaker



Spring Cloud Circuit Breaker
(Resilience4j)





Spring Cloud Circuit Breaker
(Resilience4j)





Spring Cloud Circuit Breaker
(Resilience4j)





Spring Cloud Circuit Breaker
(Resilience4j)



Spring Cloud Circuit Breaker
(Resilience4j)



Spring Cloud Circuit Breaker
(Resilience4j)



Spring Cloud Circuit Breaker
(Resilience4j)



config-server/.../compras.properties
#### DEMAIS CONFIGURAÇÕES OMITIDAS ####
spring.cloud.openfeign.circuitbreaker.enabled = true
# PRESENTING CODE

@Service
@AllArgsConstructor
public class RealizacaoDeCobranca {
private PagamentoRestClient servicoDePagamento;
private CircuitBreakerFactory cbFactory;
public ConfirmacaoPagamentoDto efetua(Compra novaCompra) {
SolicitacaoPagamentoDto payload = new SolicitacaoPagamentoDto(novaCompra);
return cbFactory.create("efetuaCobranca")
.run(() -> servicoDePagamento.efetuaCobranca(payload));
}
}compras/.../RealizacaoDeCobranca.java
E tem muito mais...
- Client-side load balancer -> Spring Cloud LoadBalancer
- API HelthCheck e Application Metrics -> Spring Boot Actuator, Spring Boot Admin
- Distributed Tracing -> Spring Cloud Sleuth
-
... e a lista continua!
Porém
CURIOSIDADE
O primeiro release candidate do Spring Cloud foi lançado em 19/12/2014.
O Kubernetes foi lançado em 09/09/2014.
E o que isso quer dizer? 🤷🏻♂️
O Spring Boot é maravilhoso para escrever uma aplicação.
Está totalmente alinhado com as práticas do manifesto Twelve-Factor App
Twelve-Factor App
- Base de Código
- Dependências
- Configurações
- Serviços de Apoio
- Construa, lance, execute
- Processos
- Vínculo de porta
- Concorrência
- Descartabilidade
- Dev/prod semelhantes
- Logs
- Processos de Admin
Tem que analisar a realidade e o ambiente da organização.
Spring Boot? Sempre!
Spring Cloud? Talvez (só o necessário).
Cácio Costa
Analista de Desenvolvimento de Negócios

https://www.linkedin.com/in/cacio-costa/
Engenheiro de software
Servidor público
Pai do Thomás
Instrutor
Músico
Capoeirista (semi-aposentado)
Spring Boot e Spring Cloud
By cacio-costa
Spring Boot e Spring Cloud
- 12