Pular para o conteúdo principal

Quiz: IoC e Fundamentos do Spring

Teste seus conhecimentos sobre Inversão de Controle e os fundamentos do Spring.

30 questões - Clique em cada pergunta para revelar a resposta.


Questões 1-10: Conceitos Básicos​

Pergunta 1: O que significa IoC (Inversão de Controle)?

Resposta: IoC (Inversão de Controle) é um princípio de design onde o controle da criação e gerenciamento dos objetos é transferido do código da aplicação para um container ou framework externo (como o Spring). Em vez do código criar suas próprias dependências, é o container que as injeta.


Pergunta 2: Qual a diferença entre IoC e DI (Injeção de Dependência)?

Resposta:

  • IoC é o princípio geral: o controle é invertido, o framework gerencia os objetos
  • DI é uma implementação específica do IoC: as dependências são injetadas pelo container

DI é uma forma de realizar o IoC. O IoC também pode ser realizado por outros padrões como o Service Locator.


Pergunta 3: O que é o container Spring (ApplicationContext)?

Resposta: O ApplicationContext é o container IoC do Spring. Ele é responsável por:

  • Instanciar os beans
  • Configurar os beans
  • Montar as dependências entre beans
  • Gerenciar o ciclo de vida dos beans

É o coração da aplicação Spring que mantém todos os objetos gerenciados.


Pergunta 4: O que é um Bean Spring?

Resposta: Um Bean Spring é um objeto que é instanciado, montado e gerenciado pelo container IoC do Spring. É simplesmente um objeto Java (POJO) cujo ciclo de vida é controlado pelo Spring ao invés do código da aplicação.


Pergunta 5: Quais são as 3 principais formas de definir um Bean?

Resposta:

  1. Anotações de estereótipo: @Component, @Service, @Repository, @Controller
  2. @Bean em uma classe @Configuration: método anotado com @Bean
  3. Configuração XML: bean (menos usado atualmente)
// 1. Anotação estereótipo
@Service
public class UserService { }

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

Pergunta 6: Qual anotação ativa o scan de componentes?

Resposta: @ComponentScan ativa o scan de componentes. Ela está incluída automaticamente em @SpringBootApplication.

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

// Ou explicitamente:
@ComponentScan(basePackages = "com.example")

Pergunta 7: Em qual package o Spring faz o scan de componentes por padrão?

Resposta: O Spring faz o scan por padrão no package da classe anotada com @SpringBootApplication e todos os seus subpackages.

Se @SpringBootApplication está em com.example.myapp, o Spring fará scan em:

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

Pergunta 8: Qual a diferença entre @Component e @Service?

Resposta: Tecnicamente, não há nenhuma diferença funcional. Ambos são estereótipos que marcam uma classe como Bean do Spring.

A diferença é semântica:

  • @Component: componente genérico
  • @Service: lógica de negócio
  • @Repository: acesso a dados (+ tradução de exceções)
  • @Controller: controlador web MVC

É para a legibilidade e intenção do código.


Pergunta 9: Por que usar IoC/DI ao invés de criar objetos com new?

Resposta: Vantagens do IoC/DI:

  1. Baixo acoplamento: classes dependem de interfaces, não de implementações
  2. Testabilidade: fácil fazer mock das dependências
  3. Flexibilidade: trocar a implementação sem modificar o código cliente
  4. Reutilização: componentes independentes
  5. Separação de responsabilidades: o código de negócio não gerencia a criação de objetos

Pergunta 10: O que é acoplamento forte (tight coupling)?

Resposta: O acoplamento forte ocorre quando uma classe depende diretamente de uma implementação concreta ao invés de uma abstração.

// Acoplamento forte (ruim)
public class OrderService {
private EmailService emailService = new EmailService(); // new = acoplamento forte
}

// Baixo acoplamento (bom)
public class OrderService {
private final NotificationService notificationService; // interface

public OrderService(NotificationService ns) { // injeção
this.notificationService = ns;
}
}

Questões 11-20: Injeção de Dependências​

Pergunta 11: Quais são os 3 tipos de injeção de dependências?

Resposta:

  1. Injeção por construtor (recomendada)
  2. Injeção por setter (@Autowired no setter)
  3. Injeção por campo (@Autowired no field)
// 1. Construtor (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. Field (evitar)
@Autowired
private UserRepository repo;

Pergunta 12: Por que a injeção por construtor é recomendada?

Resposta: A injeção por construtor é recomendada porque:

  1. Imutabilidade: dependências final, não modificáveis
  2. Obrigatória: impossível criar o objeto sem dependências
  3. Testabilidade: fácil de mockar em testes
  4. Sem @Autowired: implícito desde o Spring 4.3
  5. Detecção de ciclos: erro em tempo de compilação

Pergunta 13: Quando @Autowired é opcional?

Resposta: @Autowired é opcional desde o Spring 4.3 quando:

  • A classe tem apenas um construtor
  • Esse construtor recebe as dependências como parâmetros

O Spring detecta automaticamente e injeta as dependências.

@Service
public class UserService {
private final UserRepository repo;

// @Autowired opcional aqui (apenas um construtor)
public UserService(UserRepository repo) {
this.repo = repo;
}
}

Pergunta 14: O que acontece se o Spring encontrar vários beans do mesmo tipo?

Resposta: O Spring lança uma exceção NoUniqueBeanDefinitionException.

Soluções:

  1. @Primary no bean preferido
  2. @Qualifier("nomeDoBean") para especificar qual
  3. Injeção por nome (nome do parâmetro = nome do bean)
@Primary
@Service
public class EmailNotification implements Notification { }

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

Pergunta 15: Para que serve @Primary?

Resposta: @Primary indica qual bean usar por padrão quando existem vários beans do mesmo tipo.

@Service
@Primary // Será injetado por padrão
public class EmailNotificationService implements NotificationService { }

@Service
public class SmsNotificationService implements NotificationService { }

O bean @Primary é escolhido automaticamente, a menos que @Qualifier especifique outro.


Pergunta 16: Para que serve @Qualifier?

Resposta: @Qualifier permite especificar exatamente qual bean injetar quando existem vários candidatos.

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

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

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

Pergunta 17: É possível injetar uma List com todos os beans de um tipo?

Resposta: Sim! O Spring pode injetar uma List contendo todos os beans do tipo T.

@Service
public class NotificationManager {

private final List services;

public NotificationManager(List services) {
this.services = services; // Contém TODOS os beans NotificationService
}

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

Pergunta 18: Como tornar uma dependência opcional?

Resposta: Várias formas:

  1. @Autowired(required = false)
  2. Optional como tipo
  3. Anotação @Nullable
// Opção 1
@Autowired(required = false)
private CacheService cacheService;

// Opção 2 (recomendada)
public MyService(Optional cacheService) {
this.cacheService = cacheService.orElse(null);
}

Pergunta 19: O que é uma dependência circular?

Resposta: Uma dependência circular ocorre quando dois ou mais beans dependem um do outro, formando um 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!
}

O Spring lança uma exceção. Soluções: refatorar, usar @Lazy ou injeção por setter.


Pergunta 20: Como resolver uma dependência circular com @Lazy?

Resposta: @Lazy adia a injeção até o primeiro acesso, quebrando o ciclo.

@Service
public class A {
public A(@Lazy B b) { // B será criado depois
this.b = b;
}
}

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

Nota: O ideal é refatorar para eliminar o ciclo!


Questões 21-30: Configuração e Avançado​

Pergunta 21: Qual a diferença entre @Component e @Bean?

Resposta:

@Component@Bean
Na classeNo método
Detectado por scanEm classe @Configuration
Nome = classe (minúsculo)Nome = nome do método
Sem controle sobre criaçãoControle total sobre criação
@Component  // Auto-detectado
public class MyService { }

@Configuration
public class AppConfig {
@Bean // Criação manual
public ExternalService externalService() {
return new ExternalService("config");
}
}

Pergunta 22: Quando usar @Bean ao invés de @Component?

Resposta: Use @Bean quando:

  1. A classe vem de uma biblioteca externa (não modificável)
  2. Precisa de lógica de criação complexa
  3. Precisa de configuração antes da criação
  4. Criação de objetos de terceiros (RestTemplate, ObjectMapper)
@Bean
public RestTemplate restTemplate() {
RestTemplate rt = new RestTemplate();
rt.setErrorHandler(new CustomErrorHandler());
return rt;
}

Pergunta 23: O que é uma classe @Configuration?

Resposta: Uma classe @Configuration é uma classe especial que:

  • Contém métodos @Bean
  • É ela mesma um bean Spring
  • É tratada pelo CGLIB para garantir o singleton dos beans
  • Substitui arquivos XML de configuração
@Configuration
public class AppConfig {

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

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

Pergunta 24: O que faz @PostConstruct?

Resposta: @PostConstruct marca um método para ser executado após a injeção das dependências, para inicialização.

@Service
public class CacheService {

private final DataRepository repo;
private Map cache;

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

@PostConstruct
public void init() {
// Executado após a injeção de repo
this.cache = repo.loadInitialData();
}
}

Pergunta 25: O que faz @PreDestroy?

Resposta: @PreDestroy marca um método para ser executado antes da destruição do bean, para limpeza.

@Service
public class ConnectionPool {

private List connections;

@PreDestroy
public void cleanup() {
// Executado antes da destruição do bean
connections.forEach(Connection::close);
System.out.println("Conexões fechadas");
}
}

Pergunta 26: Qual é o escopo padrão de um bean Spring?

Resposta: O escopo padrão é Singleton: apenas uma instância do bean é criada e compartilhada em todo o contexto Spring.

Outros escopos:

  • prototype: nova instância a cada injeção
  • request: uma instância por requisição HTTP
  • session: uma instância por sessão HTTP
  • application: uma instância por ServletContext

Pergunta 27: Como mudar o escopo de um bean?

Resposta: Com a anotação @Scope:

@Service
@Scope("prototype") // Nova instância a cada injeção
public class RequestHandler { }

// Ou com a constante
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

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

Pergunta 28: O que é @Value e para que serve?

Resposta: @Value injeta valores de arquivos de propriedades ou valores padrão.

@Service
public class EmailService {

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

@Value("${app.email.enabled:true}") // Padrão: true
private boolean enabled;

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

Pergunta 29: O que é @ConfigurationProperties?

Resposta: @ConfigurationProperties vincula um grupo de propriedades a uma classe Java, mais limpo do que múltiplos @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

Pergunta 30: Como testar um serviço com dependências injetadas?

Resposta: Use mocks com 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");
}
}

A injeção por construtor torna isso possível sem o Spring.


Pontuação​

Conte suas respostas corretas:

PontuaçãoNível
27-30Excelente - Você domina IoC no Spring
21-26Bom - Pequenas revisões necessárias
15-20Médio - Releia o capítulo
Menos de 15A revisar - Refaça os fundamentos

Voltar ao Capítulo 1

Próximo Capítulo