Friends of OpenJDK Today

Spring: Internals of @ComponentScan

August 20, 2024

Author(s)

  • Avatar photo
    Mahendra Rao B

    Senior Technical Architect hailing from India with over 17 years of experience in the field. I hold a degree in Computer Science and specialize in Java, Spring, Microservices, and AWS ... Learn more

The @ComponentScan annotation, which is an interface located within the org.springframework.context.annotation package, facilitates component scanning in a Spring application. This allows the Spring Container to automatically detect beans.

Spring automatically identifies Java classes that developers mark with stereotypes like @Configuration, @Component, @Service, @Controller, and @Repository. Developers can annotate the component scan with or without parameters.

You can designate either basePackageClasses() or basePackages() (or its equivalent value()) to identify the specific packages that need to be scanned.

The @ComponentScan annotation, when used without any arguments, instructs Spring to scan the current package and all its sub-packages.

For instance:

import org.springframework.context.annotation.ComponentScan;
@ComponentScan
public class MovieApplication {
}

The @ComponentScan annotation instructs Spring to perform a scan of the specified package when you provide it with arguments, as indicated by the basePackages attribute. For instance:

import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = "com.bsmlabs.microservices")
public class MovieApplication {}

The @ComponentScan annotation acts as a substitute for the <context:component-scan/> XML tag. While it includes an annotation-config attribute, the XML version lacks this feature. In most scenarios where developers utilize @ComponentScan, they presume that default annotation configuration processing is in effect, such as the handling of @Autowired.

The component scan interface looks like

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
}

Since the RetentionPolicy of ComponentScan is Runtime, it will only execute during the runtime phase. You can apply this annotation at the class level, as well as at the interface or enum declaration levels. Therefore, you specify its @Target as ElementType with Type, specifically @Target(ElementType.TYPE).

In the SpringBootApplication class, specifies the @ComponentScan annotation at the class level to enable component scanning at runtime which helps to create

  • ApplicationContext()
  • Register Environment
  • Loads Beans Definitions
  • Applying the ApplicationContextInitializer and ApplicationContextInitilizerEvent
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

}

Attributes used with ComponentScan annotation

The value() function acts as an alias for basePackages, allowing developers to make more specific annotation declarations when they do not require additional attributes. For instance, developers can use @ComponentScan("com.bsmlabs.microservices") as an alternative to @ComponentScan(basePackages = "com.bsmlabs.microservices").

@AliasFor("basePackages")
String[] value() default {};

The basePackages() identifies annotated components, using the value as an alias for this attribute. To find a type-safe alternative to Spring-based package names, one can employ basePackageClasses.

@AliasFor("value")
String[] basePackages() default {};

For example:

import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = "com.bsmlabs.microservices")
public class MovieApplication {
}

The basePackageClasses() method outlines the process of scanning all packages that contain annotated components. This indicates that the scanning procedure will be applied to the package associated with each specified class.

For example:

import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackageClasses = {"com.bsmlabs.microservices.movie", "com.bsmlabs.microservices.payment"})
public class MovieApplication {
}

nameGenerator(): The Spring container specifically designates the BeanNameGenerator class for assigning names to the components it identifies within the ApplicationContext.

Class<? extends BeanNameGenerator> nameGenerator()
default BeanNameGenerator.class;

The inherent value of the BeanNameGenerator interface signifies that the scanner responsible for processing the @ComponentScan annotation should use its inherited bean name generator.

Default AnnotationBeanNameGenerator or any custom instance supplied to the application context at startup or bootstrap time.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FullyQualifiedAnnotationBeanNameGenerator;

@ComponentScan(nameGenerator = FullBeanNameGenerator.class)
public class MovieApplication {
}

scopeResolver: The ScopeMetadataResolver is utilized for determining the scope of identified components.

Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

For example:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ScopedProxyMode;

@ComponentScan(basePackages = "com.bsmlabs.microservices", scopeResolver = MyResolverBean.class)
public class MovieApplication {
}

scopedProxy: This specifies whether spring framework should create proxies for identified components, which may be essential when they employ scopes in a proxy-oriented manner.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ScopedProxyMode;

@ComponentScan(basePackages = "com.bsmlabs.microservices", scopedProxy = ScopedProxyMode.DEFAULT)
public class MovieApplication {
}

useDefaultFilters: This specifies the automatic detection of classes that are annotated with @Component, @Controller, @Service, and @Repository. The values can be set to either false or true, with the default being true.

boolean useDefaultFilters() default true;

For example:

import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = "com.bsmlabs.microservices", useDefaultFilters = false)
public class MovieApplication {
}

includeFilters: It delineates the types that qualify for component scanning.

Filter[] includeFilters() default {};

For example:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;

@ComponentScan(basePackages = "com.bsmlabs.microservices", includeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION))
public class MovieApplication {
}

5 Types of filter available for ComponentScan.Filter

  • FilterType.ANNOTATION : Filter candidates marked with a given annotations. It is part of package org.springframework.core.type.filter.AnnotationTypeFilter
  • FilterType.ASSIGNABLE_TYPE: Filter candidates assignable to a given type. It is part of package org.springframework.core.type.filter.AssignableTypeFilter
  • FilterType.ASPECTJ: Filter candidates matches a given AspectJ type pattern expression. It is part of package org.springframework.core.type.filter.AspectJTypeFilter
  • FilterType.REGEX: Filter candidates matching a given regex pattern. It is part of package org.springframework.core.type.filter.RegexPatternTypeFilter
  • FilterType.CUSTOM: Filter candidates using a given custom org.springframework.core.type.filter.TypeFilter

excludeFilters: It specifies which types are not eligible for component scanning.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;

@ComponentScan(basePackages = "com.bsmlabs.microservices", excludeFilters = @ComponentScan.Filter(type= FilterType.REGEX))
public class MovieApplication {
}

lazyInit(): It specifies whether scanned beans should be registered for lazy initiation.

Conclusion

The `@ComponentScan` annotation streamlines the configuration process of Spring applications by minimizing the need for developers to manually define beans, promoting a convention-over-configuration methodology, and ensuring that the application context contains the essential components.

Reference

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html

Related Articles

View All

Author(s)

  • Avatar photo
    Mahendra Rao B

    Senior Technical Architect hailing from India with over 17 years of experience in the field. I hold a degree in Computer Science and specialize in Java, Spring, Microservices, and AWS ... Learn more

Comments (6)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Samot

Clickbait. This has nothing to do with the “internals”. There are few things that could be less “internal” than the PUBLIC API of the ComponenScan annotation.

Avatar photo
Mahendra Rao B

Thanks for your feedback.

Java Weekly, Issue 557 | Baeldung

[…] >> Spring: Internals of @ComponentScan [foojay.io] […]

Avatar photo
Mahendra Rao B

Thanks Baeldung team for featuring my article in your newsletter.

Fantaman

The code snippet given as example for basePackageClasses() is actually just another example for basePackages. It should be corrected to e.g.

@ComponentScan(basePackageClasses = {"com.bsmlabs.microservices.movie", "com.bsmlabs.microservices.payment"})
public class MovieApplication {
}

And the explanation for “scopedProxy” says that “developers should create proxies” – it should probably be “the framework” or “ApplicationContext” instead of developers.

Avatar photo
Mahendra Rao B

I sincerely appreciate your time in reviewing my article and offering your feedback, Fantaman. I acknowledge that I initially overlooked certain aspects, but I have now made the necessary corrections as requested.

Thanks,
Mahendra

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard