Pular para o conteúdo principal

Quiz: Técnicas Avançadas

Teste seus conhecimentos sobre WebFlux, Redis, RabbitMQ, Scheduling e WebSockets.

30 questões - Clique em cada pergunta para revelar a resposta.


Questões 1-10: Programação Reativa (WebFlux)​

Pergunta 1: Qual a diferença entre Spring MVC e WebFlux?

Resposta:

Spring MVCWebFlux
BloqueanteNão-bloqueante
1 thread/requisiçãoEvent loop
Servlet APIReactive Streams
Tomcat, JettyNetty
Escalabilidade verticalEscalabilidade horizontal

Pergunta 2: Qual a diferença entre Mono e Flux?

Resposta:

  • Mono: 0 ou 1 elemento
  • Flux: 0 a N elementos
Mono<User> user = userRepository.findById(1L);
Flux<User> users = userRepository.findAll();

Pergunta 3: Quais são os operadores Mono/Flux mais comuns?

Resposta:

OperadorDescrição
mapTransformação síncrona
flatMapTransformação assíncrona
filterFiltragem
zipCombinar
onErrorReturnFallback de erro
switchIfEmptyFallback vazio
timeoutLimite de tempo
retryTentar novamente

Pergunta 4: Como escrever um controller reativo?

Resposta:

@RestController
@RequestMapping("/api/users")
public class UserController {

private final UserRepository repository;

@GetMapping
public Flux<User> getAll() {
return repository.findAll();
}

@GetMapping("/{id}")
public Mono<ResponseEntity<User>> getById(@PathVariable Long id) {
return repository.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Mono<User> create(@RequestBody User user) {
return repository.save(user);
}
}

Pergunta 5: O que é R2DBC?

Resposta: Reactive Relational Database Connectivity - acesso não-bloqueante a bancos relacionais.

public interface UserRepository extends ReactiveCrudRepository<User, Long> {
Flux<User> findByEmail(String email);
}

Substitui JPA/JDBC bloqueante em aplicações reativas.


Pergunta 6: Como usar o WebClient?

Resposta:

@Service
public class ExternalApiService {

private final WebClient webClient;

public Mono<Data> fetchData(String id) {
return webClient.get()
.uri("/data/{id}", id)
.retrieve()
.bodyToMono(Data.class)
.timeout(Duration.ofSeconds(5))
.retry(3);
}
}

Pergunta 7: Por que nunca chamar block() em produção?

Resposta: block() bloqueia a thread, anulando os benefícios do reativo:

  • Bloqueia o event loop
  • Reduz o throughput
  • Pode causar deadlocks

Utilize apenas em testes.


Pergunta 8: Como testar código reativo?

Resposta:

@Test
void shouldFindUser() {
Mono<User> userMono = userService.findById(1L);

StepVerifier.create(userMono)
.assertNext(user -> {
assertThat(user.getName()).isEqualTo("John");
})
.verifyComplete();
}

@Test
void shouldHandleError() {
Mono<User> userMono = userService.findById(999L);

StepVerifier.create(userMono)
.expectError(NotFoundException.class)
.verify();
}

Pergunta 9: Quando usar WebFlux?

Resposta:

  • Alta concorrência (milhares de conexões)
  • Streaming de dados
  • Aplicações em tempo real
  • Integrações com muitos chamados externos

Evite se: equipe não treinada, bibliotecas bloqueantes, CRUD simples.


Pergunta 10: Como tratar erros em reativo?

Resposta:

return userRepository.findById(id)
.switchIfEmpty(Mono.error(new NotFoundException("User not found")))
.onErrorReturn(new User("Fallback"))
.onErrorResume(e -> {
log.error("Error: {}", e.getMessage());
return Mono.empty();
});

Questões 11-17: Cache com Redis​

Pergunta 11: Como configurar Spring Cache com Redis?

Resposta:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
@Configuration
@EnableCaching
public class CacheConfig { }

Pergunta 12: Como usar @Cacheable?

Resposta:

@Cacheable(value = "users", key = "#id")
public User findById(Long id) {
log.info("Fetching from DB");
return userRepository.findById(id).orElseThrow();
}

// Primeira chamada: DB
// Próximas chamadas: cache

Pergunta 13: Qual a diferença entre @Cacheable, @CachePut e @CacheEvict?

Resposta:

AnotaçãoComportamento
@CacheableLê do cache ou executa e armazena no cache
@CachePutSempre executa e atualiza o cache
@CacheEvictRemove do cache
@CachePut(value = "users", key = "#user.id")
public User update(User user) { }

@CacheEvict(value = "users", key = "#id")
public void delete(Long id) { }

@CacheEvict(value = "users", allEntries = true)
public void clearCache() { }

Pergunta 14: Como configurar o TTL do cache?

Resposta:

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.disableCachingNullValues();

return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}

Pergunta 15: Como usar RedisTemplate diretamente?

Resposta:

@Service
public class SessionService {

private final RedisTemplate<String, Object> redisTemplate;

public void saveSession(String token, UserSession session) {
redisTemplate.opsForValue().set(
"session:" + token,
session,
Duration.ofHours(1)
);
}

public UserSession getSession(String token) {
return (UserSession) redisTemplate.opsForValue()
.get("session:" + token);
}
}

Pergunta 16: Como tratar a indisponibilidade do Redis?

Resposta:

@Configuration
public class CacheConfig extends CachingConfigurerSupport {

@Override
public CacheErrorHandler errorHandler() {
return new SimpleCacheErrorHandler() {
@Override
public void handleCacheGetError(RuntimeException ex, Cache cache, Object key) {
log.warn("Cache error: {}", ex.getMessage());
// Continuar sem cache
}
};
}
}

Pergunta 17: Quando usar cache?

Resposta:

  • Dados lidos frequentemente, alterados raramente
  • Cálculos custosos
  • Chamadas a APIs externas
  • Dados de referência (países, categorias)

Evite: dados em tempo real, dados pessoais sensíveis.


Questões 18-23: Messaging com RabbitMQ​

Pergunta 18: Como configurar RabbitMQ com Spring?

Resposta:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest

Pergunta 19: Quais são os tipos de exchange do RabbitMQ?

Resposta:

TipoRouting
DirectRouting key exata
FanoutBroadcast para todas as filas
TopicPattern matching (*.error, order.#)
HeadersBaseado em headers

Pergunta 20: Como enviar uma mensagem?

Resposta:

@Service
public class OrderProducer {

private final RabbitTemplate rabbitTemplate;

public void sendOrderEvent(OrderEvent event) {
rabbitTemplate.convertAndSend(
"order.exchange", // exchange
"order.created", // routing key
event // mensagem
);
}
}

Pergunta 21: Como receber uma mensagem?

Resposta:

@Component
public class OrderListener {

@RabbitListener(queues = "order.queue")
public void handleOrder(OrderEvent event) {
log.info("Received: {}", event);
processOrder(event);
}
}

Pergunta 22: O que é uma Dead Letter Queue?

Resposta: Fila que recebe mensagens com falha (rejeitadas, expiradas, max retries):

@Bean
public Queue orderQueue() {
return QueueBuilder.durable("order.queue")
.withArgument("x-dead-letter-exchange", "dlx.exchange")
.withArgument("x-dead-letter-routing-key", "dlq")
.build();
}

Permite analisar e reprocessar erros.


Pergunta 23: Como garantir a entrega das mensagens?

Resposta:

  1. Publisher confirms: confirmação do exchange
  2. Consumer acks: confirmação do processamento
  3. Persistent messages: sobrevive a reinício
  4. Durable queues: filas persistentes
@RabbitListener(queues = "order.queue", ackMode = "MANUAL")
public void handle(OrderEvent event, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) {
try {
process(event);
channel.basicAck(tag, false);
} catch (Exception e) {
channel.basicNack(tag, false, false);
}
}

Questões 24-27: Tarefas Agendadas​

Pergunta 24: Como ativar o scheduling?

Resposta:

@SpringBootApplication
@EnableScheduling
public class Application { }

Pergunta 25: Quais são as opções do @Scheduled?

Resposta:

// A cada 5 segundos
@Scheduled(fixedRate = 5000)

// 5 segundos após o fim
@Scheduled(fixedDelay = 5000)

// Expressão Cron
@Scheduled(cron = "0 0 6 * * *") // Todos os dias às 6h

// Com delay inicial
@Scheduled(fixedRate = 5000, initialDelay = 10000)

Pergunta 26: Como escrever uma expressão Cron?

Resposta:

┌───────────── segundo (0-59)
│ ┌───────────── minuto (0-59)
│ │ ┌───────────── hora (0-23)
│ │ │ ┌───────────── dia do mês (1-31)
│ │ │ │ ┌───────────── mês (1-12)
│ │ │ │ │ ┌───────────── dia semana (0-7)
* * * * * *

Exemplos:

  • 0 0 * * * *: a cada hora
  • 0 0 9 * * MON-FRI: 9h em dias úteis
  • 0 */15 * * * *: a cada 15 minutos

Pergunta 27: Como executar um método de forma assíncrona?

Resposta:

@EnableAsync
@Configuration
public class AsyncConfig { }

@Service
public class EmailService {

@Async
public CompletableFuture<Boolean> sendEmail(String to) {
// Executado em outra thread
return CompletableFuture.completedFuture(true);
}
}

Questões 28-30: WebSockets​

Pergunta 28: Como configurar WebSocket com STOMP?

Resposta:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
registry.setApplicationDestinationPrefixes("/app");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
}

Pergunta 29: Como enviar e receber mensagens WebSocket?

Resposta:

@Controller
public class ChatController {

@MessageMapping("/chat.send")
@SendTo("/topic/messages")
public ChatMessage send(ChatMessage message) {
return message;
}
}

// Envio programático
@Service
public class NotificationService {

private final SimpMessagingTemplate template;

public void notifyUser(String userId, Notification notif) {
template.convertAndSendToUser(userId, "/queue/notifications", notif);
}
}

Pergunta 30: Quando usar WebSocket vs REST?

Resposta:

WebSocketREST
Comunicação bidirecionalRequest-Response
Tempo realDados estáticos
Chat, notificaçõesCRUD, API
Conexão persistenteConexões curtas
Jogos, tradingAplicações tradicionais

Pontuação​

PontuaçãoNível
27-30Excelente - Técnicas avançadas dominadas
21-26Bom - Algumas revisões
15-20Médio - Releia os capítulos
Menos de 15Precisa revisar

Voltar ao Módulo 14