Quiz: Injection de Dépendances
Testez vos connaissances sur l'injection de dépendances avancée.
30 questions - Cliquez sur chaque question pour révéler la réponse.
Questions 1-15: Types d'Injection
Question 1: Quels sont les trois types d'injection de dépendances?
Réponse:
- Injection par constructeur (recommandée)
- Injection par setter
- Injection par champ (field injection)
Question 2: Pourquoi l'injection par constructeur est-elle recommandée?
Réponse:
- Dépendances immutables (final)
- Obligatoires - pas d'objet sans dépendances
- Testable - facile à mocker
- Détection des cycles à la compilation
- Pas besoin de
@Autowired(Spring 4.3+)
Question 3: Comment faire une injection par setter?
Réponse:
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
Utilisé pour les dépendances optionnelles ou reconfigurables.
Question 4: Pourquoi éviter l'injection par champ?
Réponse:
- Impossible de rendre la dépendance
final - Difficile à tester sans Spring
- Masque les dépendances (pas visible dans le constructeur)
- Facilite les violations de SRP (trop de dépendances)
// À éviter
@Autowired
private UserRepository repo;
Question 5: Quand @Autowired est-il optionnel?
Réponse: Depuis Spring 4.3, si une classe a un seul constructeur, @Autowired est implicite.
@Service
public class UserService {
private final UserRepository repo;
// @Autowired optionnel
public UserService(UserRepository repo) {
this.repo = repo;
}
}
Question 6: Comment gérer plusieurs constructeurs?
Réponse: Marquer explicitement le constructeur à utiliser:
@Service
public class UserService {
public UserService() { }
@Autowired // Spring utilisera celui-ci
public UserService(UserRepository repo) {
this.repo = repo;
}
}
Question 7: Comment rendre une dépendance optionnelle?
Réponse: Plusieurs façons:
// 1. required = false
@Autowired(required = false)
private CacheService cache;
// 2. Optional (recommandé)
public MyService(Optional<CacheService> cache) {
this.cache = cache.orElse(null);
}
// 3. @Nullable
public MyService(@Nullable CacheService cache) { }
Question 8: Comment injecter toutes les implémentations d'une interface?
Réponse:
@Service
public class NotificationManager {
private final List<NotificationService> services;
public NotificationManager(List<NotificationService> services) {
this.services = services;
}
public void notifyAll(String msg) {
services.forEach(s -> s.send(msg));
}
}
Question 9: Comment injecter un Map de beans?
Réponse:
@Service
public class ProcessorManager {
// Clé = nom du bean, Valeur = instance
private final Map<String, Processor> processors;
public ProcessorManager(Map<String, Processor> processors) {
this.processors = processors;
}
public void process(String type, Data data) {
processors.get(type).process(data);
}
}
Question 10: À quoi sert @Primary?
Réponse: Désigner le bean par défaut quand plusieurs implémentations existent:
@Service
@Primary
public class EmailNotification implements NotificationService { }
@Service
public class SmsNotification implements NotificationService { }
// EmailNotification sera injecté par défaut
Question 11: À quoi sert @Qualifier?
Réponse: Spécifier quel bean injecter:
@Service("email")
public class EmailNotification implements NotificationService { }
@Service("sms")
public class SmsNotification implements NotificationService { }
// Injection
public MyService(@Qualifier("sms") NotificationService notif) { }
Question 12: Comment créer un @Qualifier personnalisé?
Réponse:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Premium { }
@Service
@Premium
public class PremiumNotification implements NotificationService { }
// Utilisation
public MyService(@Premium NotificationService notif) { }
Question 13: Qu'est-ce que @Lazy?
Réponse: Retarde la création du bean jusqu'au premier accès:
@Service
@Lazy
public class HeavyService { }
// Ou à l'injection
public MyService(@Lazy HeavyService heavy) { }
Utilisé pour: performance au démarrage, dépendances circulaires.
Question 14: Comment résoudre une dépendance circulaire?
Réponse:
- Refactorer (meilleur choix)
- Utiliser
@Lazysur une des dépendances - Utiliser setter injection
@Service
public class A {
public A(@Lazy B b) { this.b = b; }
}
@Service
public class B {
public B(A a) { this.a = a; }
}
Question 15: Comment injecter des valeurs de configuration?
Réponse: Avec @Value:
@Service
public class EmailService {
@Value("${app.email.sender}")
private String sender;
@Value("${app.email.enabled:true}")
private boolean enabled;
// Ou via constructeur
public EmailService(@Value("${app.email.host}") String host) { }
}
Questions 16-30: Cas Avancés
Question 16: Quelle est la différence entre @Autowired et @Resource?
Réponse:
@Autowired: Spring, injection par type@Resource: Java EE (JSR-250), injection par nom
@Autowired // Par type
private UserService userService;
@Resource(name = "specificService") // Par nom
private UserService userService;
Question 17: Comment injecter le contexte Spring lui-même?
Réponse:
@Service
public class DynamicBeanLoader implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext ctx) {
this.context = ctx;
}
public Object getBean(String name) {
return context.getBean(name);
}
}
Question 18: Comment obtenir un bean de façon programmatique?
Réponse:
@Service
public class BeanFactory {
private final ApplicationContext context;
public BeanFactory(ApplicationContext context) {
this.context = context;
}
public UserService getUserService() {
return context.getBean(UserService.class);
}
}
Question 19: Qu'est-ce que ObjectProvider?
Réponse: Une façon sûre d'obtenir des beans optionnels ou multiples:
@Service
public class MyService {
private final ObjectProvider<CacheService> cacheProvider;
public MyService(ObjectProvider<CacheService> cacheProvider) {
this.cacheProvider = cacheProvider;
}
public void doWork() {
cacheProvider.ifAvailable(cache -> cache.put(...));
}
}
Question 20: Comment injecter un bean prototype dans un singleton?
Réponse: Utiliser ObjectProvider ou @Lookup:
// Option 1: ObjectProvider
@Service
public class SingletonService {
private final ObjectProvider<PrototypeBean> provider;
public void doWork() {
PrototypeBean bean = provider.getObject(); // Nouvelle instance
}
}
// Option 2: @Lookup
@Service
public abstract class SingletonService {
@Lookup
protected abstract PrototypeBean getPrototype();
}
Question 21: Qu'est-ce que @DependsOn?
Réponse: Force l'ordre de création des beans:
@Service
@DependsOn("databaseInitializer")
public class UserService {
// Créé APRÈS databaseInitializer
}
Question 22: Comment exclure un bean de l'auto-configuration?
Réponse:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApp { }
// Ou dans application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Question 23: Comment créer un bean conditionnel?
Réponse:
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public CacheManager cacheManager() { }
@Bean
@ConditionalOnMissingBean
public DefaultService defaultService() { }
@Bean
@Profile("dev")
public DevService devService() { }
Question 24: Qu'est-ce que @Order?
Réponse: Définit l'ordre de priorité pour les beans collectés:
@Component
@Order(1)
public class FirstFilter implements Filter { }
@Component
@Order(2)
public class SecondFilter implements Filter { }
// Injection dans l'ordre
public MyService(List<Filter> filters) {
// FirstFilter, SecondFilter
}
Question 25: Comment injecter l'environnement Spring?
Réponse:
@Service
public class ConfigService {
private final Environment env;
public ConfigService(Environment env) {
this.env = env;
}
public String getProperty(String key) {
return env.getProperty(key);
}
public boolean isDev() {
return Arrays.asList(env.getActiveProfiles()).contains("dev");
}
}
Question 26: Comment tester un service avec injection?
Réponse:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldFindUser() {
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
User result = userService.findById(1L);
assertThat(result).isNotNull();
}
}
Question 27: Comment injecter des propriétés groupées?
Réponse: Avec @ConfigurationProperties:
@ConfigurationProperties(prefix = "app.mail")
public class MailProperties {
private String host;
private int port;
private boolean ssl;
// getters/setters
}
// Injection
@Service
public class MailService {
public MailService(MailProperties props) { }
}
Question 28: Quelle est la différence entre @Component et @Bean?
Réponse:
| @Component | @Bean |
|---|---|
| Sur classe | Sur méthode |
| Auto-détecté par scan | Déclaré explicitement |
| Configuration limitée | Contrôle total |
Utiliser @Bean pour les classes externes ou configuration complexe.
Question 29: Comment avoir plusieurs instances du même bean?
Réponse:
@Configuration
public class DataSourceConfig {
@Bean
@Qualifier("primary")
public DataSource primaryDataSource() { }
@Bean
@Qualifier("secondary")
public DataSource secondaryDataSource() { }
}
// Injection
public MyService(
@Qualifier("primary") DataSource primary,
@Qualifier("secondary") DataSource secondary) { }
Question 30: Quels sont les problèmes courants d'injection?
Réponse:
- NoSuchBeanDefinitionException: bean manquant
- NoUniqueBeanDefinitionException: plusieurs candidats
- BeanCurrentlyInCreationException: dépendance circulaire
- UnsatisfiedDependencyException: injection échouée
Solutions: vérifier annotations, @Qualifier, @Primary, @Lazy.
Score
| Score | Niveau |
|---|---|
| 27-30 | Excellent - Injection maîtrisée |
| 21-26 | Bien - Quelques révisions |
| 15-20 | Moyen - Relisez le chapitre |
| Moins de 15 | À revoir |