Spring WebFlux - APIs Reativas para Alta Performance
Introdução ao Spring WebFlux
Com o lançamento do Spring 5, temos uma nova forma de construir APIs web: o Spring WebFlux. Este framework reativo promete revolucionar como criamos aplicações web em Java, oferecendo uma alternativa não-bloqueante ao tradicional Spring MVC.
O que é Programação Reativa?
A programação reativa é um paradigma que foca em streams de dados assíncronos e na propagação de mudanças. Em vez de bloquear threads aguardando respostas, o código reativo processa eventos conforme eles chegam.
Principais Vantagens do WebFlux
1. Alto Throughput com Menos Recursos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public Flux<User> getAllUsers() {
return userService.findAll()
.delayElements(Duration.ofMillis(100))
.doOnNext(user -> log.info("Processing user: {}", user.getName()));
}
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable String id) {
return userService.findById(id)
.switchIfEmpty(Mono.error(new UserNotFoundException(id)));
}
}
2. Melhor Utilização de Threads
O WebFlux utiliza o Event Loop, similar ao Node.js, permitindo que uma única thread processe milhares de requisições concorrentes sem bloqueio.
3. Composabilidade e Operadores Funcionais
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service
public class OrderService {
public Mono<OrderResponse> processOrder(OrderRequest request) {
return validateOrder(request)
.flatMap(this::checkInventory)
.flatMap(this::calculatePrice)
.flatMap(this::processPayment)
.map(this::createResponse)
.onErrorMap(PaymentException.class,
ex -> new OrderProcessingException("Payment failed", ex));
}
private Mono<Order> validateOrder(OrderRequest request) {
return Mono.fromCallable(() -> {
// Validação assíncrona
return new Order(request);
}).subscribeOn(Schedulers.boundedElastic());
}
}
4. Integração com Bancos de Dados Reativos
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Repository
public class ReactiveUserRepository {
private final R2dbcEntityTemplate template;
public Flux<User> findByAge(int minAge) {
return template.select(User.class)
.matching(Query.query(where("age").greaterThanOrEquals(minAge)))
.all();
}
public Mono<User> save(User user) {
return template.insert(User.class)
.using(user);
}
}
Quando Usar WebFlux vs Spring MVC
Use WebFlux quando:
- Alta concorrência: Muitas requisições simultâneas
- I/O intensivo: Chamadas para APIs externas, banco de dados
- Streaming: Dados em tempo real
- Microserviços: Comunicação não-bloqueante entre serviços
Use Spring MVC quando:
- Aplicações CRUD simples: Operações síncronas básicas
- Equipe experiente: Time já familiarizado com o modelo tradicional
- Bibliotecas bloqueantes: Dependências que não suportam reatividade
Exemplo: API de Streaming de Dados
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RestController
public class StreamingController {
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<String>> streamEvents() {
return Flux.interval(Duration.ofSeconds(1))
.map(sequence -> ServerSentEvent.<String>builder()
.id(String.valueOf(sequence))
.event("periodic-event")
.data("Event " + sequence + " at " + LocalTime.now())
.build());
}
@GetMapping("/news")
public Flux<News> getLatestNews() {
return newsService.getStreamingNews()
.take(Duration.ofMinutes(5))
.filter(news -> news.getCategory().equals("TECH"));
}
}
Testando APIs Reativas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
@Autowired
private WebTestClient webTestClient;
@Test
void shouldReturnAllUsers() {
webTestClient.get()
.uri("/users")
.exchange()
.expectStatus().isOk()
.expectBodyList(User.class)
.hasSize(3)
.consumeWith(response -> {
List<User> users = response.getResponseBody();
assertThat(users).extracting(User::getName)
.containsExactly("Alice", "Bob", "Charlie");
});
}
}
Desafios e Considerações
- Curva de Aprendizado: Paradigma diferente do desenvolvimento tradicional
- Debugging: Stack traces podem ser mais complexos
- Ecossistema: Nem todas as bibliotecas suportam reatividade
- Context Switching: Cuidado com blocking calls em código reativo
Conclusão
O Spring WebFlux representa uma evolução natural para aplicações que precisam de alta performance e escalabilidade. Embora tenha uma curva de aprendizado, os benefícios em termos de throughput e utilização de recursos fazem dele uma excelente escolha para APIs modernas.
Para sistemas que lidam com alta concorrência, streaming de dados ou integração com múltiplos serviços, o WebFlux oferece uma solução elegante e performática que pode transformar significativamente a arquitetura de suas aplicações.