Spring Component Scan
4 CommentsLast Updated on June 5, 2019 by Michelle Mesiona
When developing Spring Boot applications, you need to tell the Spring Framework where to look for Spring components. Using component scan is one method of asking Spring to detect Spring managed components. Spring needs the information to locate and register all the Spring components with the application context when the application starts.
Spring can auto scan, detect, and instantiate components from pre-defined project packages. It can auto scan all classes annotated with the stereotype annotations @Component
, @Controller
, @Service
, and @Repository
In this post, I will discuss how Spring component scanning works.
Sample Application
Let us create a simple Spring Boot application to understand how component scanning works in Spring.
We will start by writing few components.
DemoBeanA.java
//package guru.springframework.blog.componentscan.example.demopackageA; import org.springframework.stereotype.Component; @Component("demoBeanA") public class DemoBeanA { }
DemoBeanB1.java
//404: Not Found
DemoBeanB2.java
//package guru.springframework.blog.componentscan.example.demopackageB; import org.springframework.stereotype.Component; @Component("demoBeanB2") public class DemoBeanB2 extends DemoBeanB1{ }
DemoBeanB3.java
//package guru.springframework.blog.componentscan.example.demopackageB; import org.springframework.stereotype.Component; @Component("demoBeanB3") public class DemoBeanB3 extends DemoBeanB2{ }
DemoBeanC.java
//package guru.springframework.blog.componentscan.example.demopackageC; import org.springframework.stereotype.Component; @Component("demoBeanC") public class DemoBeanC { }
DemoBeanD.java
package guru.springframework.blog.componentscan.example.demopackageD; import org.springframework.stereotype.Component; @Component("demoBeanD") public class DemoBeanD { }
The @SpringBootApplication Annotation
Spring needs to know which packages to scan for annotated components in order to add them to the IoC container. In a Spring Boot project, we typically set the main application class with the @SpringBootApplication
annotation. Under the hood, @SpringBootApplication
is a composition of the @Configuration
, @ComponentScan
, and @EnableAutoConfiguration
annotations. With this default setting, Spring Boot will auto scan for components in the current package (containing the @SpringBoot main class) and its sub packages.
To know more about these annotations, go through my Spring Framework Annotations post.
Note: It is recommended that you locate your main application class in a root package above the component classes of the application.
The code to create the main class and access components is this.
BlogPostsApplication.java
//package guru.springframework.blog; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; @SpringBootApplication public class BlogPostsApplication { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(BlogPostsApplication.class,args); System.out.println("Contains A "+context. containsBeanDefinition("demoBeanA")); System.out.println("Contains B2 " + context. containsBeanDefinition("demoBeanB2")); System.out.println("Contains C " + context. containsBeanDefinition("demoBeanC")); } }
The output of running the main class is this.
As you can notice, all the classes in the sub packages of the main class BlogPostsApplication
are auto scanned by Spring.
@ComponentScan – Identifying Base Packages
The @ComponentScan
annotation is used with the @Configuration
annotation to tell Spring the packages to scan for annotated components. @ComponentScan
is also used to specify base packages and base package classes using thebasePackageClasses
or basePackages
attributes of @ComponentScan
.
The basePackageClasses
attribute is a type-safe alternative to basePackages
. When you specify basePackageClasses, Spring will scan the package (and subpackages) of the classes you specify.
A Java class annotated with @ComponentScan
with the basePackageClassesattribute
is this.
BlogPostsApplicationWithComponentScan.java
//package guru.springframework.blog; import guru.springframework.blog.componentscan.example.demopackageB.DemoBeanB1; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = {"guru.springframework.blog.componentscan.example.demopackageA", "guru.springframework.blog.componentscan.example.demopackageD", "guru.springframework.blog.componentscan.example.demopackageE"}, basePackageClasses = DemoBeanB1.class) public class BlogPostsApplicationWithComponentScan { public static void main(String[] args) { ApplicationContext context = SpringApplication. run(BlogPostsApplicationWithComponentScan.class,args); System.out.println("Contains A "+context. containsBeanDefinition("demoBeanA")); System.out.println("Contains B2 " + context. containsBeanDefinition("demoBeanB2")); System.out.println("Contains C " + context. containsBeanDefinition("demoBeanC")); System.out.println("Contains D " + context. containsBeanDefinition("demoBeanD")); } }
The output on running the main class is this.
The @ComponentScan
annotation uses the basePackages
attribute to specify three packages (and subpackages) that will be scanned by Spring. The annotation also uses the basePackageClasses
attribute to declare the DemoBeanB1
class, whose package Spring Boot should scan.
As demoBeanC
is in a different package, Spring did not find it during component scanning.
Component Scanning Filters
You can configure component scanning by using different type filters that Spring provides.
By using filters, you can further narrow the set of candidate components from everything in basePackages to everything in the base packages that matches the given filter or filters.
Filters can be of two types: include and exclude filters. As their names suggest, include filters specify which types are eligible for component scanning, while exclude filters specify which types are not.
You can use the include and/or exclude filters with or without the default filter. To disable the default filter, set the useDefaultFilters
element of the @ComponentScan
annotation to a false
.
The code to disable the default filter is this.
BlogPostsApplicationDisablingDefaultFilters.java
//package guru.springframework.blog; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(value = "guru.springframework.blog.componentscan.example.demopackageA", useDefaultFilters = false) public class BlogPostsApplicationDisablingDefaultFilters { public static void main(String[] args) { ApplicationContext context = SpringApplication. run(BlogPostsApplicationDisablingDefaultFilters.class,args); System.out.println("Contains A " + context.containsBean("demoBeanA")); } }
In the preceding code, the value member defines the specific guru.springframework.blog.componentscan.example.demopackageA
package to scan, while the useDefaultFilters
member disables the default filter.
The output on running the main class is this.
As you can notice, the class DemoBeanA
in the package demopackageA
is unavailable when the useDefaultFilters
element of the @ComponentScan
annotation is set to a false.
Component Scanning Filter Types
Spring provides the FilterType
enumeration for the type filters that may be used in conjunction with @ComponentScan
.
The available FilterType
values are:
FilterType.ANNOTATION
: Include or exclude those classes with a stereotype annotationFilterType.ASPECTJ
: Include or exclude classes using an AspectJ type pattern expressionFilterType.ASSIGNABLE_TYPE
: Include or exclude classes that extend or implement this class or interfaceFilterType.REGEX
: Include or exclude classes using a regular expressionFilterType.CUSTOM
: Include or exclude classes using a custom implementation of theorg.springframework.core.type.TypeFilter
interface
Include Filters
With include filters, you can include certain classes to be scanned by Spring. To include assignable type, use the includeFilters
element of the @ComponentScan
annotation with FilterType. ASSIGNABLE_TYPE
. Using this filter, you can instruct Spring to scan for classes that extends or implements the class or interface you specify.
The code to use the includeFilters
element of @ComponentScan
is this.
BlogPostsApplicationIncludeFilter.java
//package guru.springframework.blog; import guru.springframework.blog.componentscan.example.demopackageB.DemoBeanB2; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration @ComponentScan(basePackages = {"guru.springframework.blog.componentscan.example.demopackageA", "guru.springframework.blog.componentscan.example.demopackageB"}, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = DemoBeanB2.class), useDefaultFilters = false) public class BlogPostsApplicationIncludeFilter { public static void main(String[] args) { ApplicationContext context = SpringApplication. run(BlogPostsApplicationIncludeFilter.class,args); System.out.println("Contains A " + context.containsBean("demoBeanA")); System.out.println("Contains B1 " + context.containsBean("demoBeanB1")); System.out.println("Contains B2 " + context.containsBean("demoBeanB2")); System.out.println("Contains B3 " + context.containsBean("demoBeanB3")); } }
The output on running the main class is this.
As shown in the preceding figure, Spring detected and used the demoBean3
component that extends demoBean2
.
Include Filters using Regex
You can use regular expressions to filter out components to be scanned by Spring. Use the includeFilters
nested annotation @ComponentScan.Filter
type FilterType.REGEX
to set a pattern.
The code to use an exclude filter based on regular expression is this.
BlogPostsApplicationFilterTypeRegex.java
//package guru.springframework.blog; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration @ComponentScan(useDefaultFilters = false, includeFilters = @ComponentScan.Filter (type = FilterType.REGEX, pattern = ".*[A2]")) public class BlogPostsApplicationFilterTypeRegex { public static void main(String[] args) { ApplicationContext context = SpringApplication. run(BlogPostsApplicationFilterTypeRegex.class,args); System.out.println("Contains A " + context.containsBean("demoBeanA")); System.out.println("Contains B1 " + context.containsBean("demoBeanB1")); System.out.println("Contains B2 " + context.containsBean("demoBeanB2")); } }
The output of the code snippet is this.
As shown in the preceding figure, the classes whose names end with A or 2 are detected by Spring.
Exclude Filters
The @ComponentScan
annotation enables you to exclude those classes that you do not want to scan.
The code to use an exclude filter is this.
BlogPostsApplicationExcludeFilter.java
//package guru.springframework.blog; import guru.springframework.blog.componentscan.example.demopackageB.DemoBeanB1; import guru.springframework.blog.componentscan.example.demopackageB.DemoBeanB2; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; @Configuration @ComponentScan(basePackageClasses = {DemoBeanB1.class}, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = DemoBeanB2.class)) public class BlogPostsApplicationExcludeFilter { public static void main(String[] args) { ApplicationContext context = SpringApplication. run(BlogPostsApplicationExcludeFilter.class,args); System.out.println("Contains B1 " + context.containsBean("demoBeanB1")); System.out.println("Contains B2 " + context.containsBean("demoBeanB2")); } }
In this code, the nested annotation @ComponentScan.Filter
is used to specify the filter type as FilterType.ASSIGNABLE_TYPE
and the base class that should be excluded from scanning.
As you can see, the class DemoBeanB2
has been excluded from being scanned.
Summary
The default auto scanning will work for your Spring Boot project most of the time. You only need to ensure that your @SpringBoot
main class is at the base package of your package hierarchy. Spring Boot will automatically perform a component scan in the package of the Spring Boot main class and below.
One related annotation that I didn’t mention in this post is @EntityScan
is more about JPA entity scanning rather than component scanning. Unlike @ComponentScan, the @EntityScan annotation
does not create beans. It only identifies which classes should be used by a specific persistence context.
Armen
Very well summarized blog, Thank you!
Amine
How do you configure your springboot app to scan programatically a package? I am trying to figure out a way when my springboot pickup jars in its classpath and scan them these jars might have different packages unknown at deployment. E.g. I want to discover all jars that annotate ServerEndPoint websocket. Thanks.
Philip Dilip
Our legacy application is referring Spring v3.2.2
FilterType.REGEX is unavailable in it
Can you please clarify the version from which, REGEX was introduced?