Saltar al contenido principal

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:

  1. Inyección por constructor (recomendada)
  2. Inyección por setter
  3. 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:

  1. Refactorizar (mejor opción)
  2. Usar @Lazy en una de las dependencias
  3. 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 claseSobre método
Auto-detectado por scanDeclarado explícitamente
Configuración limitadaControl 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:

  1. NoSuchBeanDefinitionException: bean faltante
  2. NoUniqueBeanDefinitionException: múltiples candidatos
  3. BeanCurrentlyInCreationException: dependencia circular
  4. UnsatisfiedDependencyException: inyección fallida

Soluciones: verificar anotaciones, @Qualifier, @Primary, @Lazy.


Puntaje​

PuntajeNivel
27-30Excelente - Dominio de la inyección
21-26Bien - Algunas revisiones
15-20Medio - Repase el capítulo
Menos de 15A revisar

Volver al Módulo 5