03 - Spring @ComponentScan Anotação
O que é a anotação @ComponentScan?
É uma anotação do Spring responsável por escanear pacotes automaticamente e detectar classes gerenciadas pelo Spring (Beans). Como, por exemplo:
- @RestController
- @Service
- @Repository
- @Component
- @Configuration
Na maioria das aplicações Spring Boot, você não precisa declarar @ComponentScan explicitamente porque @SpringBootApplication já a inclui.
@SpringBootApplication é composta por:
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
O que ela faz?
- Escanear os pacotes configurados
- Encontrar classes anotadas com estereótipos do Spring
- Criar instâncias de Bean
- Registrar os Beans no ApplicationContext
- Resolver dependências (@Autowired, injeção por construtor, etc.)
Application starts
│
▼
@ComponentScan
│
▼
Search packages
│
▼
Find annotated classes
│
▼
Create Beans
│
▼
Register in ApplicationContext
Exemplos
Exemplo básico
@Configuration
@ComponentScan("com.mycompany")
public class AppConfig {
}
Escanear múltiplos pacotes
@Configuration
@ComponentScan({
"com.mycompany.api",
"com.mycompany.secret",
"com.mycompany.payment"
})
public class AppConfig {
}
Filtrando componentes
É possível incluir ou excluir classes específicas. Este recurso é comumente usado em configurações avançadas ou testes.
# Exclude
@ComponentScan(
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Repository.class
)
)
# Include
@ComponentScan(
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Repository.class
)
)
Erros comuns
Bean não encontrado - NoSuchBeanDefinitionException
Causa raiz:
- a classe está fora do pacote escaneado.
- anotação ausente: @Component, @Service, etc
Escanear pacotes desnecessários
Isso faz com que o Spring escaneie um grande número de classes desnecessárias, aumentando o tempo de inicialização da aplicação e causando conflitos. É preferível ser mais específico.
# Wrong
@ComponentScan("com")
# Right
@ComponentScan("com.mycompany")
Beans duplicados
Dois componentes implementando a mesma interface podem causar: NoUniqueBeanDefinitionException
@Service
class PaypalService implements PaymentService {
}
@Service
class StripeService implements PaymentService{
}
# your application calls
@Autowired
PaymentService paymentService;
Este erro não é causado diretamente por @ComponentScan. Ele ocorre porque o escaneamento de componentes registra ambos os Beans no ApplicationContext.
Comportamento de Escaneamento Padrão
Por padrão, @ComponentScan escaneia o pacote onde a classe principal da aplicação está localizada e todos os seus subpacotes.
Exemplo:
com.example ├── Application ├── controller ├── service └── repository
Como Application está localizada em com.example, todos os subpacotes são escaneados automaticamente.
Se um Bean estiver localizado fora desta hierarquia de pacotes, ele não será detectado a menos que você configure explicitamente @ComponentScan.