Saltar al contenido principal

Quiz: IoC y Fundamentos de Spring

Ponga a prueba sus conocimientos sobre Inversión de Control y los fundamentos de Spring.

30 preguntas - Haga clic en cada pregunta para revelar la respuesta.


Preguntas 1-10: Conceptos Básicos​

Pregunta 1: ¿Qué significa IoC (Inversion of Control)?

Respuesta: IoC (Inversión de Control) es un principio de diseño donde el control de la creación y gestión de los objetos se transfiere del código de la aplicación a un contenedor o framework externo (como Spring). En lugar de que el código cree sus propias dependencias, es el contenedor quien las inyecta.


Pregunta 2: ¿Cuál es la diferencia entre IoC y DI (Dependency Injection)?

Respuesta:

  • IoC es el principio general: el control se invierte, el framework gestiona los objetos
  • DI es una implementación específica de IoC: las dependencias son inyectadas por el contenedor

DI es una forma de realizar IoC. IoC también puede lograrse mediante otros patrones como Service Locator.


Pregunta 3: ¿Qué es el contenedor Spring (ApplicationContext)?

Respuesta: El ApplicationContext es el contenedor IoC de Spring. Es responsable de:

  • Instanciar los beans
  • Configurar los beans
  • Ensamblar las dependencias entre beans
  • Gestionar el ciclo de vida de los beans

Es el núcleo de la aplicación Spring que mantiene todos los objetos gestionados.


Pregunta 4: ¿Qué es un Bean de Spring?

Respuesta: Un Bean de Spring es un objeto que es instanciado, ensamblado y gestionado por el contenedor IoC de Spring. Es simplemente un objeto Java (POJO) cuyo ciclo de vida es controlado por Spring en lugar del código de la aplicación.


Pregunta 5: ¿Cuáles son las 3 formas principales de definir un Bean?

Respuesta:

  1. Anotaciones de estereotipo: @Component, @Service, @Repository, @Controller
  2. @Bean en una clase @Configuration: método anotado con @Bean
  3. Configuración XML: bean (menos usado hoy en día)
// 1. Anotación de estereotipo
@Service
public class UserService { }

// 2. @Bean
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}

Pregunta 6: ¿Qué anotación activa el escaneo de componentes?

Respuesta: @ComponentScan activa el escaneo de componentes. Está incluida automáticamente en @SpringBootApplication.

@SpringBootApplication // incluye @ComponentScan
public class MyApplication { }

// O explícitamente:
@ComponentScan(basePackages = "com.example")

Pregunta 7: ¿En qué paquete escanea Spring los componentes por defecto?

Respuesta: Spring escanea por defecto el paquete de la clase anotada con @SpringBootApplication y todos sus subpaquetes.

Si @SpringBootApplication está en com.example.myapp, Spring escaneará:

  • com.example.myapp
  • com.example.myapp.service
  • com.example.myapp.controller
  • etc.

Pregunta 8: ¿Cuál es la diferencia entre @Component y @Service?

Respuesta: Técnicamente, no hay ninguna diferencia funcional. Ambos son estereotipos que marcan una clase como Bean de Spring.

La diferencia es semántica:

  • @Component: componente genérico
  • @Service: lógica de negocio
  • @Repository: acceso a datos (+ traducción de excepciones)
  • @Controller: controlador web MVC

Es para la legibilidad y la intención del código.


Pregunta 9: ¿Por qué usar IoC/DI en lugar de crear los objetos con new?

Respuesta: Ventajas de IoC/DI:

  1. Bajo acoplamiento: clases dependientes de interfaces, no de implementaciones
  2. Testabilidad: fácil de mockear las dependencias
  3. Flexibilidad: cambiar la implementación sin modificar el código cliente
  4. Reutilizabilidad: componentes independientes
  5. Separación de preocupaciones: el código de negocio no gestiona la creación de objetos

Pregunta 10: ¿Qué es el acoplamiento fuerte (tight coupling)?

Respuesta: El acoplamiento fuerte ocurre cuando una clase depende directamente de una implementación concreta en lugar de una abstracción.

// Acoplamiento fuerte (malo)
public class OrderService {
private EmailService emailService = new EmailService(); // new = acoplamiento fuerte
}

// Bajo acoplamiento (bueno)
public class OrderService {
private final NotificationService notificationService; // interfaz

public OrderService(NotificationService ns) { // inyección
this.notificationService = ns;
}
}

Preguntas 11-20: Inyección de Dependencias​

Pregunta 11: ¿Cuáles son los 3 tipos de inyección de dependencias?

Respuesta:

  1. Inyección por constructor (recomendada)
  2. Inyección por setter (@Autowired en el setter)
  3. Inyección por campo (@Autowired en el campo)
// 1. Constructor (recomendado)
public class UserService {
private final UserRepository repo;
public UserService(UserRepository repo) { this.repo = repo; }
}

// 2. Setter
@Autowired
public void setRepository(UserRepository repo) { this.repo = repo; }

// 3. Campo (evitar)
@Autowired
private UserRepository repo;

Pregunta 12: ¿Por qué se recomienda la inyección por constructor?

Respuesta: La inyección por constructor es recomendada porque:

  1. Inmutabilidad: dependencias final, no modificables
  2. Obligatoria: imposible crear el objeto sin dependencias
  3. Testabilidad: fácil de mockear en pruebas
  4. Sin @Autowired: implícito desde Spring 4.3
  5. Detección de ciclos: error en compilación

Pregunta 13: ¿Cuándo es opcional @Autowired?

Respuesta: @Autowired es opcional desde Spring 4.3 cuando:

  • La clase tiene un solo constructor
  • Ese constructor recibe las dependencias como parámetros

Spring detecta automáticamente e inyecta las dependencias.

@Service
public class UserService {
private final UserRepository repo;

// @Autowired opcional aquí (un solo constructor)
public UserService(UserRepository repo) {
this.repo = repo;
}
}

Pregunta 14: ¿Qué ocurre si Spring encuentra varios beans del mismo tipo?

Respuesta: Spring lanza una excepción NoUniqueBeanDefinitionException.

Soluciones:

  1. @Primary en el bean preferido
  2. @Qualifier("nombreDelBean") para especificar cuál
  3. Inyección por nombre (nombre del parámetro = nombre del bean)
@Primary
@Service
public class EmailNotification implements Notification { }

// o
@Autowired
@Qualifier("smsNotification")
private Notification notification;

Pregunta 15: ¿Para qué sirve @Primary?

Respuesta: @Primary indica qué bean usar por defecto cuando existen varios beans del mismo tipo.

@Service
@Primary // Será inyectado por defecto
public class EmailNotificationService implements NotificationService { }

@Service
public class SmsNotificationService implements NotificationService { }

El bean @Primary se elige automáticamente salvo que @Qualifier especifique otro.


Pregunta 16: ¿Para qué sirve @Qualifier?

Respuesta: @Qualifier permite especificar exactamente qué bean inyectar cuando existen varios candidatos.

@Service("emailService")
public class EmailNotification implements Notification { }

@Service("smsService")
public class SmsNotification implements Notification { }

// Uso
@Autowired
@Qualifier("smsService")
private Notification notification;

Pregunta 17: ¿Se puede inyectar una List de todos los beans de un tipo?

Respuesta: ¡Sí! Spring puede inyectar una List que contenga todos los beans del tipo T.

@Service
public class NotificationManager {

private final List services;

public NotificationManager(List services) {
this.services = services; // Contiene TODOS los beans NotificationService
}

public void notifyAll(String message) {
services.forEach(s -> s.send(message));
}
}

Pregunta 18: ¿Cómo hacer que una dependencia sea opcional?

Respuesta: Varias formas:

  1. @Autowired(required = false)
  2. Optional como tipo
  3. Anotación @Nullable
// Opción 1
@Autowired(required = false)
private CacheService cacheService;

// Opción 2 (recomendada)
public MyService(Optional cacheService) {
this.cacheService = cacheService.orElse(null);
}

Pregunta 19: ¿Qué es una dependencia circular?

Respuesta: Una dependencia circular ocurre cuando dos o más beans dependen uno del otro, formando un ciclo.

@Service
public class A {
public A(B b) { } // A depende de B
}

@Service
public class B {
public B(A a) { } // B depende de A -> ¡CICLO!
}

Spring lanza una excepción. Soluciones: refactorizar, usar @Lazy, o inyección por setter.


Pregunta 20: ¿Cómo resolver una dependencia circular con @Lazy?

Respuesta: @Lazy retrasa la inyección hasta el primer acceso, rompiendo el ciclo.

@Service
public class A {
public A(@Lazy B b) { // B se creará más tarde
this.b = b;
}
}

@Service
public class B {
public B(A a) {
this.a = a;
}
}

Nota: ¡Es mejor refactorizar para eliminar el ciclo!


Preguntas 21-30: Configuración y Avanzado​

Pregunta 21: ¿Cuál es la diferencia entre @Component y @Bean?

Respuesta:

@Component@Bean
En una claseEn un método
Detectado por escaneoEn clase @Configuration
Nombre = clase (minúscula)Nombre = nombre del método
Sin control sobre la creaciónControl total sobre la creación
@Component  // Auto-detectado
public class MyService { }

@Configuration
public class AppConfig {
@Bean // Creación manual
public ExternalService externalService() {
return new ExternalService("config");
}
}

Pregunta 22: ¿Cuándo usar @Bean en lugar de @Component?

Respuesta: Use @Bean cuando:

  1. La clase proviene de una librería externa (no modificable)
  2. Se necesita lógica de creación compleja
  3. Se necesita configuración antes de la creación
  4. Creación de objetos de terceros (RestTemplate, ObjectMapper)
@Bean
public RestTemplate restTemplate() {
RestTemplate rt = new RestTemplate();
rt.setErrorHandler(new CustomErrorHandler());
return rt;
}

Pregunta 23: ¿Qué es una clase @Configuration?

Respuesta: Una clase @Configuration es una clase especial que:

  • Contiene métodos @Bean
  • Es en sí misma un bean de Spring
  • Es tratada por CGLIB para garantizar el singleton de los beans
  • Reemplaza los archivos XML de configuración
@Configuration
public class AppConfig {

@Bean
public DataSource dataSource() { ... }

@Bean
public JdbcTemplate jdbcTemplate(DataSource ds) {
return new JdbcTemplate(ds); // ds inyectado
}
}

Pregunta 24: ¿Qué hace @PostConstruct?

Respuesta: @PostConstruct marca un método para ejecutarse después de la inyección de dependencias, para inicialización.

@Service
public class CacheService {

private final DataRepository repo;
private Map cache;

public CacheService(DataRepository repo) {
this.repo = repo;
}

@PostConstruct
public void init() {
// Ejecutado después de la inyección de repo
this.cache = repo.loadInitialData();
}
}

Pregunta 25: ¿Qué hace @PreDestroy?

Respuesta: @PreDestroy marca un método para ejecutarse antes de la destrucción del bean, para limpieza.

@Service
public class ConnectionPool {

private List connections;

@PreDestroy
public void cleanup() {
// Ejecutado antes de la destrucción del bean
connections.forEach(Connection::close);
System.out.println("Conexiones cerradas");
}
}

Pregunta 26: ¿Cuál es el ámbito por defecto de un bean de Spring?

Respuesta: El ámbito por defecto es Singleton: se crea una sola instancia del bean y se comparte en todo el contexto de Spring.

Otros ámbitos:

  • prototype: nueva instancia en cada inyección
  • request: una instancia por petición HTTP
  • session: una instancia por sesión HTTP
  • application: una instancia por ServletContext

Pregunta 27: ¿Cómo cambiar el ámbito de un bean?

Respuesta: Con la anotación @Scope:

@Service
@Scope("prototype") // Nueva instancia en cada inyección
public class RequestHandler { }

// O con la constante
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

// Para scopes web
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)

Pregunta 28: ¿Qué es @Value y para qué sirve?

Respuesta: @Value inyecta valores desde archivos de propiedades o valores por defecto.

@Service
public class EmailService {

@Value("${app.email.sender}")
private String senderEmail;

@Value("${app.email.enabled:true}") // Por defecto: true
private boolean enabled;

@Value("#{systemProperties['user.name']}") // SpEL
private String systemUser;
}

Pregunta 29: ¿Qué es @ConfigurationProperties?

Respuesta: @ConfigurationProperties enlaza un grupo de propiedades a una clase Java, más limpio que múltiples @Value.

@ConfigurationProperties(prefix = "app.email")
public class EmailProperties {
private String sender;
private boolean enabled;
private int maxRetries;
// getters/setters
}

// application.yml
app:
email:
sender: noreply@example.com
enabled: true
max-retries: 3

Pregunta 30: ¿Cómo probar un servicio con dependencias inyectadas?

Respuesta: Utilice mocks con Mockito:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {

@Mock
private UserRepository userRepository;

@InjectMocks
private UserService userService;

@Test
void shouldFindUser() {
// Given
when(userRepository.findById(1L))
.thenReturn(Optional.of(new User(1L, "John")));

// When
User user = userService.findById(1L);

// Then
assertThat(user.getName()).isEqualTo("John");
}
}

La inyección por constructor hace esto posible sin Spring.


Puntuación​

Cuente sus respuestas correctas:

PuntuaciónNivel
27-30Excelente - Usted domina IoC en Spring
21-26Bien - Algunas revisiones menores
15-20Medio - Repase el capítulo
Menos de 15A repasar - Revise los fundamentos

Volver al Capítulo 1

Siguiente Capítulo