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

  1. Base de Código
  2. Dependências
  3. Configurações
  4. Serviços de Apoio
  5. Construa, lance, execute
  6. Processos
  7. Vínculo de porta
  8. Concorrência
  9. Descartabilidade
  10. Dev/prod semelhantes
  11. Logs
  12. 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