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 MVC | WebFlux |
|---|---|
| Bloqueante | Não-bloqueante |
| 1 thread/requisição | Event loop |
| Servlet API | Reactive Streams |
| Tomcat, Jetty | Netty |
| Escalabilidade vertical | Escalabilidade horizontal |
Pergunta 2: Qual a diferença entre Mono e Flux?
Resposta:
Mono: 0 ou 1 elementoFlux: 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:
| Operador | Descrição |
|---|---|
map | Transformação síncrona |
flatMap | Transformação assíncrona |
filter | Filtragem |
zip | Combinar |
onErrorReturn | Fallback de erro |
switchIfEmpty | Fallback vazio |
timeout | Limite de tempo |
retry | Tentar 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ção | Comportamento |
|---|---|
@Cacheable | Lê do cache ou executa e armazena no cache |
@CachePut | Sempre executa e atualiza o cache |
@CacheEvict | Remove 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:
| Tipo | Routing |
|---|---|
| Direct | Routing key exata |
| Fanout | Broadcast para todas as filas |
| Topic | Pattern matching (*.error, order.#) |
| Headers | Baseado 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:
- Publisher confirms: confirmação do exchange
- Consumer acks: confirmação do processamento
- Persistent messages: sobrevive a reinício
- 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 hora0 0 9 * * MON-FRI: 9h em dias úteis0 */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:
| WebSocket | REST |
|---|---|
| Comunicação bidirecional | Request-Response |
| Tempo real | Dados estáticos |
| Chat, notificações | CRUD, API |
| Conexão persistente | Conexões curtas |
| Jogos, trading | Aplicações tradicionais |
Pontuação
| Pontuação | Nível |
|---|---|
| 27-30 | Excelente - Técnicas avançadas dominadas |
| 21-26 | Bom - Algumas revisões |
| 15-20 | Médio - Releia os capítulos |
| Menos de 15 | Precisa revisar |