Spring Component Scan

Spring Component Scan

4 Comments

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 {
}
Spring Framework 5
Click Here to Become a Spring Framework Guru!

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.
Output of BlogPostsApplication.java class

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.
Output of BlogPostsApplicationWithComponentScan.java Class

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.
Output of BlogPostsApplicationDisablingDefaultFilters.java Class

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 annotation
  • FilterType.ASPECTJ: Include or exclude classes using an AspectJ type pattern expression
  • FilterType.ASSIGNABLE_TYPE: Include or exclude classes that extend or implement this class or interface
  • FilterType.REGEX: Include or exclude classes using a regular expression
  • FilterType.CUSTOM: Include or exclude classes using a custom implementation of the org.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.
Output of BlogPostsApplicationIncludeFilter.java Class

As shown in the preceding figure, Spring detected and used the demoBean3 component that extends demoBean2.

Spring Framework 5
Learn Spring Framework 5 with my Spring Framework 5: Beginner to Guru course!

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.
Output of BlogPostsApplicationFilterTypeRegex.java Class
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.

The output is this.
Output of using the FilterType.ASSIGNABLE_TYPE type

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.

About jt

    You May Also Like

    4 comments on “Spring Component Scan

    1. May 3, 2018 at 7:59 pm

      Very well summarized blog, Thank you!

      Reply
    2. August 22, 2018 at 3:23 pm

      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.

      Reply
    3. October 15, 2018 at 10:00 pm

      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?

      Reply

    Leave a Reply

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

    This site uses Akismet to reduce spam. Learn how your comment data is processed.