Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Exploring Spring @Component Scanning Across Different Applications

Tech 1

Example One: Basic Spring Application \[The SampleBean class uses the @Component ennotation too indciate it should be managed by Spring.\njava\n@Component \\[public class SampleBean { \\ private String identifier = "sampleBean"; \\ public String getIdentifier() { \\ return identifier; \\ } \\ public void setIdentifier(String identifier) { \\ this.identifier = identifier; \\ } \\}\n\nThe AppSetup class, annotated with @Configuration and @ComponentScan, specifies that Spring should scan the com.demo package for components.\njava\n@Configuration \\[@ComponentScan("com.demo") \\[public class AppSetup { }\n\nIn the MainApp class, an AnnotationConfigApplicationContext is created with AppSetup as a parameter. This context is then used to retrieve and print the identifier of SampleBean.\njava\npublic class MainApp { \\ public static void main(String[] args) { \\ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppSetup.class); \\ SampleBean bean = context.getBean(SampleBean.class); \\ System.out.println(bean.getIdentifier()); \\ } \\}\n\n### Example Two: Spring Web Application \[The CoreConfig class scans the com.demo package excluding controllers.\njava\n@Configuration \\[@ComponentScan(\\ basePackages = "com.demo", \\ excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class)}\\)\npublic class CoreConfig {}\n\nThe WebConfig class scans the com.demo.controller package and sets up a view resolver.\njava\n@Configuration \\[@EnableWebMvc \\[@ComponentScan(basePackages = "com.demo.controller") \\[public class WebConfig implements WebMvcConfigurer { \\ @Bean \\ public ViewResolver viewResolver() { \\ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); \\ resolver.setPrefix("/WEB-INF/views/"); \\ resolver.setSuffix(".jsp"); \\ return resolver; \\ } \\}\n\nThe WebAppInitializer class configures the web application context using CoreConfig and WebConfig.\njava\npublic class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { \\ @Override \\ protected Class<?>[] getRootConfigClasses() { \\ return new Class<?>[] { CoreConfig.class }; \\ } \\ @Override \\ protected Class<?>[] getServletConfigClasses() { \\ return new Class<?>[] { WebConfig.class }; \\ } \\ @Override \\ protected String[] getServletMappings() { \\ return new String[] { "/" }; \\ } \\}\n\nThe GreetingController injects SampleBean and prints its identifier when handling requests.\njava\n@Controller \\[public class GreetingController { \\ @Autowired \\ private SampleBean sampleBean; \\ @GetMapping("/greet") \\ public String greet(Model model) { \\ System.out.println(sampleBean.getIdentifier()); \\ return "greet"; \\ } \\}\n\n### Example Three: Spring Boot Application \[In a Spring Boot application, AppLauncher uses the @SpringBootApplication annotation which includes @Configuration and @ComponentScan.\njava\n@SpringBootApplication \\[public class AppLauncher { \\ public static void main(String[] args) { \\ SpringApplication.run(AppLauncher.class, args); \\ } \\}\n\nThe GreetingController remains the same as in Example Two.\n### Under the Hood \[Spring uses BeanDefinitionRegistryPostProcessor to register beans. The ConfigurationClassPostProcessor processes configuration classes annotated with @Configuration and @ComponentScan to identify and register beans.\njava\npublic class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {\\ @Override \\ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { \\ processConfigBeanDefinitions(registry); \\ }\\}\n\nThe ConfigurationClassParser parses configuration classes and delegates to ComponentScanAnnotationParser to handle @ComponentScan annotations.\njava\nclass ConfigurationClassParser { \\ protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException { \\ sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); \\ } \\}\n\nThe ComponentScanAnnotationParser uses ClassPathBeanDefinitionScanner to scan specified packages and register beans annotated with @Component.\njava\npublic Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, String declaringClass) { \\ ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters")); \\ Set<String> basePackages = new LinkedHashSet<>(); \\ String[] basePackagesArray = componentScan.getStringArray("basePackages"); \\ for (String pkg : basePackagesArray) { \\ Collections.addAll(basePackages, StringUtils.tokenizeToStringArray(pkg, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); \\ } \\ return scanner.doScan(StringUtils.toStringArray(basePackages)); \\}\n\nThe ClassPathBeanDefinitionScanner scans the classpath for classes annotated with @Component and registers them with the Spring container.\njava\nprotected Set<BeanDefinitionHolder> doScan(String... basePackages) { \\ Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); \\ for (String basePackage : basePackages) { \\ Set<BeanDefinition> candidates = findCandidateComponents(basePackage); \\ for (BeanDefinition candidate : candidates) { \\ BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); \\ registerBeanDefinition(definitionHolder, this.registry); \\ beanDefinitions.add(definitionHolder); \\ } \\ } \\ return beanDefinitions; \\}\n\nIn a Spring Boot application, SpringApplication initializes the context and loads bean definitions using BeanDefinitionLoader.\njava\npublic class SpringApplication { \\ public ConfigurableApplicationContext run(String... args) { \\ ConfigurableApplicationContext context = createApplicationContext(); \\ prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); \\ refreshContext(context); \\ return context; \\ } \\}\n\nThe BeanDefinitionLoader utilizes AnnotatedBeanDefinitionReader to register configuration classes.\njava\nclass BeanDefinitionLoader { \\ private void load(Object source) { \\ if (source instanceof Class<?> type) { \\ load(type); \\ } \\ } \\ private void load(Class<?> source) { \\ if (isEligible(source)) { \\ this.annotatedReader.register(source); \\ } \\ } \\}\n\n

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.