Quiz: Inyección de Dependencias
Ponga a prueba sus conocimientos sobre inyección de dependencias avanzada.
30 preguntas - Haga clic en cada pregunta para revelar la respuesta.
Preguntas 1-15: Tipos de Inyección
Pregunta 1: ¿Cuáles son los tres tipos de inyección de dependencias?
Respuesta:
- Inyección por constructor (recomendada)
- Inyección por setter
- Inyección por campo (field injection)
Pregunta 2: ¿Por qué se recomienda la inyección por constructor?
Respuesta:
- Dependencias inmutables (final)
- Obligatorias - no hay objeto sin dependencias
- Testeable - fácil de mockear
- Detección de ciclos en compilación
- No necesita
@Autowired(Spring 4.3+)
Pregunta 3: ¿Cómo se realiza una inyección por setter?
Respuesta:
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
Se utiliza para dependencias opcionales o reconfigurables.
Pregunta 4: ¿Por qué evitar la inyección por campo?
Respuesta:
- Imposible hacer la dependencia
final - Difícil de testear sin Spring
- Oculta las dependencias (no visible en el constructor)
- Facilita violaciones de SRP (demasiadas dependencias)
// A evitar
@Autowired
private UserRepository repo;
Pregunta 5: ¿Cuándo es opcional @Autowired?
Respuesta: Desde Spring 4.3, si una clase tiene un solo constructor, @Autowired es implícito.
@Service
public class UserService {
private final UserRepository repo;
// @Autowired opcional
public UserService(UserRepository repo) {
this.repo = repo;
}
}
Pregunta 6: ¿Cómo manejar múltiples constructores?
Respuesta: Marcar explícitamente el constructor a utilizar:
@Service
public class UserService {
public UserService() { }
@Autowired // Spring usará este
public UserService(UserRepository repo) {
this.repo = repo;
}
}
Pregunta 7: ¿Cómo hacer que una dependencia sea opcional?
Respuesta: Varias maneras:
// 1. required = false
@Autowired(required = false)
private CacheService cache;
// 2. Optional (recomendado)
public MyService(Optional<CacheService> cache) {
this.cache = cache.orElse(null);
}
// 3. @Nullable
public MyService(@Nullable CacheService cache) { }
Pregunta 8: ¿Cómo inyectar todas las implementaciones de una interfaz?
Respuesta:
@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));
}
}
Pregunta 9: ¿Cómo inyectar un Map de beans?
Respuesta:
@Service
public class ProcessorManager {
// Clave = nombre del bean, Valor = instancia
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);
}
}
Pregunta 10: ¿Para qué sirve @Primary?
Respuesta: Designar el bean por defecto cuando existen varias implementaciones:
@Service
@Primary
public class EmailNotification implements NotificationService { }
@Service
public class SmsNotification implements NotificationService { }
// EmailNotification será inyectado por defecto
Pregunta 11: ¿Para qué sirve @Qualifier?
Respuesta: Especificar qué bean inyectar:
@Service("email")
public class EmailNotification implements NotificationService { }
@Service("sms")
public class SmsNotification implements NotificationService { }
// Inyección
public MyService(@Qualifier("sms") NotificationService notif) { }
Pregunta 12: ¿Cómo crear un @Qualifier personalizado?
Respuesta:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Premium { }
@Service
@Premium
public class PremiumNotification implements NotificationService { }
// Uso
public MyService(@Premium NotificationService notif) { }
Pregunta 13: ¿Qué es @Lazy?
Respuesta: Retrasa la creación del bean hasta el primer acceso:
@Service
@Lazy
public class HeavyService { }
// O en la inyección
public MyService(@Lazy HeavyService heavy) { }
Usado para: rendimiento al inicio, dependencias circulares.
Pregunta 14: ¿Cómo resolver una dependencia circular?
Respuesta:
- Refactorizar (mejor opción)
- Usar
@Lazyen una de las dependencias - Usar inyección por setter
@Service
public class A {
public A(@Lazy B b) { this.b = b; }
}
@Service
public class B {
public B(A a) { this.a = a; }
}
Pregunta 15: ¿Cómo inyectar valores de configuración?
Respuesta: Con @Value:
@Service
public class EmailService {
@Value("${app.email.sender}")
private String sender;
@Value("${app.email.enabled:true}")
private boolean enabled;
// O vía constructor
public EmailService(@Value("${app.email.host}") String host) { }
}
Preguntas 16-30: Casos Avanzados
Pregunta 16: ¿Cuál es la diferencia entre @Autowired y @Resource?
Respuesta:
@Autowired: Spring, inyección por tipo@Resource: Java EE (JSR-250), inyección por nombre
@Autowired // Por tipo
private UserService userService;
@Resource(name = "specificService") // Por nombre
private UserService userService;
Pregunta 17: ¿Cómo inyectar el contexto de Spring en sí mismo?
Respuesta:
@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);
}
}
Pregunta 18: ¿Cómo obtener un bean de forma programática?
Respuesta:
@Service
public class BeanFactory {
private final ApplicationContext context;
public BeanFactory(ApplicationContext context) {
this.context = context;
}
public UserService getUserService() {
return context.getBean(UserService.class);
}
}
Pregunta 19: ¿Qué es ObjectProvider?
Respuesta: Una forma segura de obtener beans opcionales o múltiples:
@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(...));
}
}
Pregunta 20: ¿Cómo inyectar un bean prototype en un singleton?
Respuesta: Usar ObjectProvider o @Lookup:
// Opción 1: ObjectProvider
@Service
public class SingletonService {
private final ObjectProvider<PrototypeBean> provider;
public void doWork() {
PrototypeBean bean = provider.getObject(); // Nueva instancia
}
}
// Opción 2: @Lookup
@Service
public abstract class SingletonService {
@Lookup
protected abstract PrototypeBean getPrototype();
}
Pregunta 21: ¿Qué es @DependsOn?
Respuesta: Fuerza el orden de creación de los beans:
@Service
@DependsOn("databaseInitializer")
public class UserService {
// Creado DESPUÉS de databaseInitializer
}
Pregunta 22: ¿Cómo excluir un bean de la auto-configuración?
Respuesta:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MyApp { }
// O en application.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Pregunta 23: ¿Cómo crear un bean condicional?
Respuesta:
@Bean
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public CacheManager cacheManager() { }
@Bean
@ConditionalOnMissingBean
public DefaultService defaultService() { }
@Bean
@Profile("dev")
public DevService devService() { }
Pregunta 24: ¿Qué es @Order?
Respuesta: Define el orden de prioridad para los beans recolectados:
@Component
@Order(1)
public class FirstFilter implements Filter { }
@Component
@Order(2)
public class SecondFilter implements Filter { }
// Inyección en orden
public MyService(List<Filter> filters) {
// FirstFilter, SecondFilter
}
Pregunta 25: ¿Cómo inyectar el entorno de Spring?
Respuesta:
@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");
}
}
Pregunta 26: ¿Cómo testear un servicio con inyección?
Respuesta:
@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();
}
}
Pregunta 27: ¿Cómo inyectar propiedades agrupadas?
Respuesta: Con @ConfigurationProperties:
@ConfigurationProperties(prefix = "app.mail")
public class MailProperties {
private String host;
private int port;
private boolean ssl;
// getters/setters
}
// Inyección
@Service
public class MailService {
public MailService(MailProperties props) { }
}
Pregunta 28: ¿Cuál es la diferencia entre @Component y @Bean?
Respuesta:
| @Component | @Bean |
|---|---|
| Sobre clase | Sobre método |
| Auto-detectado por scan | Declarado explícitamente |
| Configuración limitada | Control total |
Usar @Bean para clases externas o configuración compleja.
Pregunta 29: ¿Cómo tener múltiples instancias del mismo bean?
Respuesta:
@Configuration
public class DataSourceConfig {
@Bean
@Qualifier("primary")
public DataSource primaryDataSource() { }
@Bean
@Qualifier("secondary")
public DataSource secondaryDataSource() { }
}
// Inyección
public MyService(
@Qualifier("primary") DataSource primary,
@Qualifier("secondary") DataSource secondary) { }
Pregunta 30: ¿Cuáles son los problemas comunes de inyección?
Respuesta:
- NoSuchBeanDefinitionException: bean faltante
- NoUniqueBeanDefinitionException: múltiples candidatos
- BeanCurrentlyInCreationException: dependencia circular
- UnsatisfiedDependencyException: inyección fallida
Soluciones: verificar anotaciones, @Qualifier, @Primary, @Lazy.
Puntaje
| Puntaje | Nivel |
|---|---|
| 27-30 | Excelente - Dominio de la inyección |
| 21-26 | Bien - Algunas revisiones |
| 15-20 | Medio - Repase el capítulo |
| Menos de 15 | A revisar |