Quiz: Beans et Contexte Spring
Testez vos connaissances sur les beans et le contexte applicatif.
30 questions - Cliquez sur chaque question pour révéler la réponse.
Questions 1-15: Beans
Question 1: Qu'est-ce qu'un bean Spring?
Réponse: Un bean est un objet géré par le conteneur Spring IoC:
- Créé et configuré par Spring
- Injection de dépendances automatique
- Cycle de vie géré
- Singleton par défaut
Question 2: Comment déclarer un bean avec une annotation?
Réponse:
// Avec stéréotype (scan automatique)
@Component
public class MyService { }
@Service
public class UserService { }
@Repository
public class UserRepository { }
@Controller
public class UserController { }
Question 3: Comment déclarer un bean avec @Bean?
Réponse:
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.registerModule(new JavaTimeModule());
}
}
Question 4: Quelle est la différence entre @Component et @Bean?
Réponse:
| @Component | @Bean |
|---|---|
| Sur une classe | Sur une méthode |
| Auto-détecté par scan | Déclaré explicitement |
| Classes que vous contrôlez | Classes tierces |
| Configuration limitée | Contrôle total |
Question 5: Quel est le nom par défaut d'un bean?
Réponse: Le nom de la classe en camelCase:
@Component
public class UserService { }
// Nom: userService
@Bean
public RestTemplate myRestTemplate() { }
// Nom: myRestTemplate
Personnaliser:
@Component("customName")
@Bean("customName")
Question 6: Comment récupérer un bean par son nom?
Réponse:
@Autowired
private ApplicationContext context;
public void example() {
UserService service = context.getBean("userService", UserService.class);
// Ou par type
UserService service = context.getBean(UserService.class);
}
Question 7: Qu'est-ce que le cycle de vie d'un bean?
Réponse:
- Instanciation: création de l'objet
- Injection: injection des dépendances
- Initialisation: méthodes @PostConstruct
- Utilisation: bean prêt
- Destruction: méthodes @PreDestroy
Question 8: Comment exécuter du code après l'initialisation?
Réponse:
@Component
public class DataLoader {
@PostConstruct
public void init() {
log.info("Bean initialisé");
loadData();
}
}
// Ou avec @Bean
@Bean(initMethod = "init")
public MyService myService() { }
Question 9: Comment exécuter du code avant la destruction?
Réponse:
@Component
public class ResourceManager {
@PreDestroy
public void cleanup() {
log.info("Nettoyage des ressources");
closeConnections();
}
}
// Ou avec @Bean
@Bean(destroyMethod = "close")
public DataSource dataSource() { }
Question 10: Qu'est-ce que InitializingBean et DisposableBean?
Réponse: Interfaces alternatives pour le cycle de vie:
@Component
public class MyBean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() {
// Après injection
}
@Override
public void destroy() {
// Avant destruction
}
}
Préférer @PostConstruct/@PreDestroy pour moins de couplage.
Question 11: Comment implémenter ApplicationRunner?
Réponse:
@Component
public class StartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
log.info("Application démarrée");
// Arguments: args.getOptionValues("config")
}
}
Exécuté après le démarrage complet du contexte.
Question 12: Comment implémenter CommandLineRunner?
Réponse:
@Component
public class DataInitializer implements CommandLineRunner {
private final UserRepository repository;
@Override
public void run(String... args) {
repository.save(new User("Admin"));
log.info("Données initialisées");
}
}
Question 13: Comment ordonner l'exécution des runners?
Réponse:
@Component
@Order(1)
public class FirstRunner implements CommandLineRunner { }
@Component
@Order(2)
public class SecondRunner implements CommandLineRunner { }
Question 14: Comment créer un bean conditionnel?
Réponse:
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public CacheManager cacheManager() { }
@Bean
@ConditionalOnMissingBean(DataSource.class)
public DataSource defaultDataSource() { }
@Bean
@Profile("dev")
public DevService devService() { }
Question 15: Qu'est-ce que @Lazy?
Réponse: Retarde la création du bean au premier accès:
@Component
@Lazy
public class HeavyService {
public HeavyService() {
// Appelé seulement au premier accès
}
}
// Ou à l'injection
public MyController(@Lazy HeavyService service) { }
Questions 16-30: Contexte et Scopes
Question 16: Qu'est-ce que l'ApplicationContext?
Réponse: Le conteneur central de Spring qui:
- Gère tous les beans
- Fournit l'injection de dépendances
- Publie des événements
- Charge les ressources
- Gère l'internationalisation
Question 17: Quels sont les scopes de beans disponibles?
Réponse:
| Scope | Description |
|---|---|
singleton | Une instance par contexte (défaut) |
prototype | Nouvelle instance à chaque demande |
request | Une instance par requête HTTP |
session | Une instance par session HTTP |
application | Une instance par ServletContext |
Question 18: Comment définir le scope d'un bean?
Réponse:
@Component
@Scope("prototype")
public class PrototypeBean { }
@Bean
@Scope("request")
public RequestContext requestContext() { }
// Ou avec constantes
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Question 19: Quel problème survient en injectant un prototype dans un singleton?
Réponse: Le singleton garde toujours la même instance du prototype:
@Component // Singleton
public class SingletonService {
private final PrototypeBean proto; // Toujours la même instance!
public SingletonService(PrototypeBean proto) {
this.proto = proto;
}
}
Solution: utiliser ObjectProvider ou @Lookup.
Question 20: Comment utiliser ObjectProvider?
Réponse:
@Component
public class SingletonService {
private final ObjectProvider<PrototypeBean> protoProvider;
public void doWork() {
PrototypeBean proto = protoProvider.getObject(); // Nouvelle instance
}
}
Question 21: Comment utiliser @Lookup?
Réponse:
@Component
public abstract class SingletonService {
@Lookup
protected abstract PrototypeBean getPrototype();
public void doWork() {
PrototypeBean proto = getPrototype(); // Nouvelle instance
}
}
Question 22: Comment écouter les événements du contexte?
Réponse:
@Component
public class ContextListener {
@EventListener
public void onContextRefreshed(ContextRefreshedEvent event) {
log.info("Contexte rafraîchi");
}
@EventListener
public void onContextClosed(ContextClosedEvent event) {
log.info("Contexte fermé");
}
}
Question 23: Comment publier un événement personnalisé?
Réponse:
// Événement
public class UserCreatedEvent extends ApplicationEvent {
private final User user;
public UserCreatedEvent(Object source, User user) {
super(source);
this.user = user;
}
}
// Publication
@Service
public class UserService {
private final ApplicationEventPublisher publisher;
public void createUser(User user) {
userRepository.save(user);
publisher.publishEvent(new UserCreatedEvent(this, user));
}
}
// Écoute
@Component
public class UserEventListener {
@EventListener
public void onUserCreated(UserCreatedEvent event) {
log.info("Utilisateur créé: {}", event.getUser().getName());
}
}
Question 24: Comment écouter un événement de façon asynchrone?
Réponse:
@EnableAsync
@Configuration
public class AsyncConfig { }
@Component
public class AsyncListener {
@Async
@EventListener
public void onEvent(MyEvent event) {
// Exécuté dans un autre thread
}
}
Question 25: Comment accéder à l'environnement Spring?
Réponse:
@Component
public class ConfigService {
private final Environment env;
public ConfigService(Environment env) {
this.env = env;
}
public void showConfig() {
String property = env.getProperty("app.name");
String[] profiles = env.getActiveProfiles();
boolean isDev = env.acceptsProfiles(Profiles.of("dev"));
}
}
Question 26: Comment charger des ressources externes?
Réponse:
@Component
public class ResourceLoader {
@Value("classpath:data/config.json")
private Resource configResource;
public void load() throws IOException {
String content = new String(configResource.getInputStream().readAllBytes());
}
}
Question 27: Comment implémenter EnvironmentPostProcessor?
Réponse:
public class CustomEnvProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
// Modifier l'environnement avant le démarrage
Map<String, Object> props = new HashMap<>();
props.put("custom.property", "value");
env.getPropertySources().addFirst(new MapPropertySource("custom", props));
}
}
Enregistrer dans META-INF/spring.factories.
Question 28: Comment utiliser les profils Spring?
Réponse:
// Bean actif uniquement en dev
@Component
@Profile("dev")
public class DevOnlyService { }
// Bean actif sauf en prod
@Component
@Profile("!prod")
public class NonProdService { }
// Plusieurs profils
@Component
@Profile({"dev", "test"})
public class DevTestService { }
Question 29: Comment définir des beans dans des configurations séparées?
Réponse:
@Configuration
public class DatabaseConfig {
@Bean
public DataSource dataSource() { }
}
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain() { }
}
@Configuration
@Import({DatabaseConfig.class, SecurityConfig.class})
public class AppConfig { }
Question 30: Comment tester un contexte Spring?
Réponse:
@SpringBootTest
class ContextTest {
@Autowired
private ApplicationContext context;
@Test
void contextLoads() {
assertThat(context).isNotNull();
assertThat(context.getBean(UserService.class)).isNotNull();
}
@Test
void beanExists() {
assertThat(context.containsBean("userService")).isTrue();
}
}
Score
| Score | Niveau |
|---|---|
| 27-30 | Excellent - Beans et contexte maîtrisés |
| 21-26 | Bien - Quelques révisions |
| 15-20 | Moyen - Relisez le chapitre |
| Moins de 15 | À revoir |