Understanding Spring @Component Scanning Through Three Practical Examples
Example 1: Basic Spring Application
The following demonstrates a simple bean registration using @Component annotation:
@Component
public class ServiceInstance {
private String identifier = "serviceInstance";
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
}
@Configuration
@ComponentScan("com.example")
public class ApplicationConfig {
}
public class Bootstrap {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
ServiceInstance instance = context.getBean(ServiceInstance.class);
System.out.println(instance.getIdentifier());
}
}
Example 2: Spring Web Application
This configuration separates web and root contexts with specific scanning filters:
@Component
public class ServiceInstance {
private String identifier = "serviceInstance";
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
}
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
@Configuration
@ComponentScan(
basePackages = "com.example",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)
}
)
public class RootConfiguration {
}
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example.controller")
public class WebConfiguration implements WebMvcConfigurer {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
@Controller
public class GreetingController {
@Autowired
private ServiceInstance serviceInstance;
@GetMapping("/greet")
public String handleGreeting(Model model) {
System.out.println(serviceInstance.getIdentifier());
return "greeting";
}
}
Example 3: Spring Boot Application
Spring Boot simplifies configuration through auto-configuraton:
@Component
public class ServiceInstance {
private String identifier = "serviceInstance";
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
}
@Controller
public class GreetingController {
@Autowired
private ServiceInstance serviceInstance;
@GetMapping("/greet")
public String handleGreeting(Model model) {
System.out.println(serviceInstance.getIdentifier());
return "greeting";
}
}
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
Component Scanning Mechanism
Spring's componant scanning operates through a sequence of steps during context initialization. When the application context starts, configuration classes annotated with @Configuration are registered as bean definitions. The ConfigurationClassPostProcessor, implementing BeanDefinitionRegistryPostProcessor, processes these definisions.
During processing, it identifies @ComponentScan annotations on configuration classes and extracts their basePackages attributes. Using this information, Spring traverses specified packages, reading class files and checking for component annotations like @Component. Classes with these annotations are converted into bean definitions and registered within the application context.
This mechanism ensures that beans are automatically discovered and made available for dependency injection throughout the application lifecycle.