Aller au contenu principal

Quiz: Techniques Avancées

Testez vos connaissances sur WebFlux, Redis, RabbitMQ, Scheduling et WebSockets.

30 questions - Cliquez sur chaque question pour révéler la réponse.


Questions 1-10: Programmation Réactive (WebFlux)​

Question 1: Quelle est la différence entre Spring MVC et WebFlux?

Réponse:

Spring MVCWebFlux
BloquantNon-bloquant
1 thread/requêteEvent loop
Servlet APIReactive Streams
Tomcat, JettyNetty
Scalabilité verticaleScalabilité horizontale

Question 2: Quelle est la différence entre Mono et Flux?

Réponse:

  • Mono: 0 ou 1 élément
  • Flux: 0 à N éléments
Mono<User> user = userRepository.findById(1L);
Flux<User> users = userRepository.findAll();

Question 3: Quels sont les opérateurs Mono/Flux courants?

Réponse:

OpérateurDescription
mapTransformation synchrone
flatMapTransformation async
filterFiltrage
zipCombiner
onErrorReturnFallback erreur
switchIfEmptyFallback vide
timeoutLimite de temps
retryRéessayer

Question 4: Comment écrire un contrôleur réactif?

Réponse:

@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);
}
}

Question 5: Qu'est-ce que R2DBC?

Réponse: Reactive Relational Database Connectivity - accès non-bloquant aux bases relationnelles.

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

Remplace JPA/JDBC bloquant dans les applications réactives.


Question 6: Comment utiliser WebClient?

Réponse:

@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);
}
}

Question 7: Pourquoi ne jamais appeler block() en production?

Réponse: block() bloque le thread, annulant les avantages du réactif:

  • Bloque l'event loop
  • Réduit le throughput
  • Peut causer des deadlocks

Utiliser uniquement dans les tests.


Question 8: Comment tester du code réactif?

Réponse:

@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();
}

Question 9: Quand utiliser WebFlux?

Réponse:

  • Haute concurrence (milliers de connexions)
  • Streaming de données
  • Applications temps réel
  • Intégrations avec beaucoup d'appels externes

Éviter si: équipe non formée, bibliothèques bloquantes, CRUD simple.


Question 10: Comment gérer les erreurs en réactif?

Réponse:

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();
});

Questions 11-17: Cache avec Redis​

Question 11: Comment configurer Spring Cache avec Redis?

Réponse:

<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 { }

Question 12: Comment utiliser @Cacheable?

Réponse:

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

// Premier appel: DB
// Appels suivants: cache

Question 13: Quelle est la différence entre @Cacheable, @CachePut et @CacheEvict?

Réponse:

AnnotationComportement
@CacheableLit du cache ou exécute et cache
@CachePutToujours exécute et met à jour le cache
@CacheEvictSupprime du 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() { }

Question 14: Comment configurer le TTL du cache?

Réponse:

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

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

Question 15: Comment utiliser RedisTemplate directement?

Réponse:

@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);
}
}

Question 16: Comment gérer l'indisponibilité de Redis?

Réponse:

@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());
// Continuer sans cache
}
};
}
}

Question 17: Quand mettre en cache?

Réponse:

  • Données lues fréquemment, modifiées rarement
  • Calculs coûteux
  • Appels API externes
  • Données de référence (pays, catégories)

Éviter: données temps réel, données personnelles sensibles.


Questions 18-23: Messaging avec RabbitMQ​

Question 18: Comment configurer RabbitMQ avec Spring?

Réponse:

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

Question 19: Quels sont les types d'exchange RabbitMQ?

Réponse:

TypeRouting
DirectRouting key exact
FanoutBroadcast à toutes les queues
TopicPattern matching (*.error, order.#)
HeadersBasé sur les headers

Question 20: Comment envoyer un message?

Réponse:

@Service
public class OrderProducer {

private final RabbitTemplate rabbitTemplate;

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

Question 21: Comment recevoir un message?

Réponse:

@Component
public class OrderListener {

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

Question 22: Qu'est-ce qu'une Dead Letter Queue?

Réponse: Queue qui reçoit les messages en échec (rejetés, expirés, 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();
}

Permet d'analyser et retraiter les erreurs.


Question 23: Comment garantir la livraison des messages?

Réponse:

  1. Publisher confirms: confirmation de l'échange
  2. Consumer acks: confirmation du traitement
  3. Persistent messages: survit au redémarrage
  4. Durable queues: queues persistantes
@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);
}
}

Questions 24-27: Tâches Planifiées​

Question 24: Comment activer le scheduling?

Réponse:

@SpringBootApplication
@EnableScheduling
public class Application { }

Question 25: Quelles sont les options de @Scheduled?

Réponse:

// Toutes les 5 secondes
@Scheduled(fixedRate = 5000)

// 5 secondes après la fin
@Scheduled(fixedDelay = 5000)

// Expression Cron
@Scheduled(cron = "0 0 6 * * *") // Tous les jours à 6h

// Avec délai initial
@Scheduled(fixedRate = 5000, initialDelay = 10000)

Question 26: Comment écrire une expression Cron?

Réponse:

┌───────────── seconde (0-59)
│ ┌───────────── minute (0-59)
│ │ ┌───────────── heure (0-23)
│ │ │ ┌───────────── jour du mois (1-31)
│ │ │ │ ┌───────────── mois (1-12)
│ │ │ │ │ ┌───────────── jour semaine (0-7)
* * * * * *

Exemples:

  • 0 0 * * * *: toutes les heures
  • 0 0 9 * * MON-FRI: 9h en semaine
  • 0 */15 * * * *: toutes les 15 minutes

Question 27: Comment exécuter une méthode de façon asynchrone?

Réponse:

@EnableAsync
@Configuration
public class AsyncConfig { }

@Service
public class EmailService {

@Async
public CompletableFuture<Boolean> sendEmail(String to) {
// Exécuté dans un autre thread
return CompletableFuture.completedFuture(true);
}
}

Questions 28-30: WebSockets​

Question 28: Comment configurer WebSocket avec STOMP?

Réponse:

@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();
}
}

Question 29: Comment envoyer et recevoir des messages WebSocket?

Réponse:

@Controller
public class ChatController {

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

// Envoi programmatique
@Service
public class NotificationService {

private final SimpMessagingTemplate template;

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

Question 30: Quand utiliser WebSocket vs REST?

Réponse:

WebSocketREST
Communication bidirectionnelleRequest-Response
Temps réelDonnées statiques
Chat, notificationsCRUD, API
Connexion persistanteConnexions courtes
Jeux, tradingApplications classiques

Score​

ScoreNiveau
27-30Excellent - Techniques avancées maîtrisées
21-26Bien - Quelques révisions
15-20Moyen - Relisez les chapitres
Moins de 15À revoir

Retour au Module 14