@ComponentScan in SpringBoot

  • First @Configurations are scanned before @Components by @ComponentScan
  • Hence configurations are annotated with @ComponentScan to direct Spring to those Components that are required for the @Configuration
  • Secondly, all the Components are scanned

While developing an application, we need to tell the Spring framework to look for Spring-managed components. @ComponentScan enables Spring to scan for things like configurations, controllers, services, and other components we define.

In particular, the @ComponentScanannotation is used with @Configuration annotation to specify the package for Spring to scan for components:

@Configuration
@ComponentScan
public class EmployeeApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(EmployeeApplication.class, args);
        // ...
    }
}

Alternatively, Spring can also start scanning from the specified package, which we can define using basePackageClasses() or basePackages()If no package is specified, then it considers the package of the class declaring the @ComponentScan annotation as the starting package:

package com.baeldung.annotations.componentscanautoconfigure;

// ...

@Configuration
@ComponentScan(basePackages = {"com.baeldung.annotations.componentscanautoconfigure.healthcare",
  "com.baeldung.annotations.componentscanautoconfigure.employee"},
  basePackageClasses = Teacher.class)
public class EmployeeApplication {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(EmployeeApplication.class, args);
        // ...
    }
}

In the example, Spring will scan the healthcare and employee packages and the Teacher class for components.

Spring searches the specified packages along with all its sub-packages for classes annotated with @ConfigurationAdditionallythe Configuration classes can contain @Bean annotations, which register the methods as beans in the Spring application context. After that, the @ComponentScan annotation can auto-detect such beans:

@Configuration
public class Hospital {
    @Bean
    public Doctor getDoctor() {
        return new Doctor();
    }
}

Furthermore, the @ComponentScan annotation can also scan, detect, and register beans for classes annotated with @Component, @Controller, @Service, and @Repository.

For example, we can create an Employee class as a component which can be scanned by the @ComponentScan annotation:

@Component("employee")
public class Employee {
    // ...
}

Note : ComponentScan is not ment to scan all the @Componets and @Beans, it is ment to register a group of Packages from which it can find its configuration files and @EnableAutoConfiguration annotation should be used that the scan all class purpose, hence to be put in root class. And @EnableAutoConfiguration comes by default with @SpringBootApplication

ComponentScan Without Arguments

With Spring, we use the @ComponentScan annotation along with the @Configuration annotation to specify the packages that we want to be scanned. @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.

Let’s say we have the following @Configuration in com.baeldung.componentscan.springapp package:

@Configuration
@ComponentScan
public class SpringComponentScanApp {
    private static ApplicationContext applicationContext;

    @Bean
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }

    public static void main(String[] args) {
        applicationContext = 
          new AnnotationConfigApplicationContext(SpringComponentScanApp.class);

        for (String beanName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanName);
        }
    }
}

In addition, we have the Cat and Dog components in com.baeldung.componentscan.springapp.animals package:

package com.baeldung.componentscan.springapp.animals;
// ...
@Component
public class Cat {}
package com.baeldung.componentscan.springapp.animals;
// ...
@Component
public class Dog {}

Finally, we have the Rose component in com.baeldung.componentscan.springapp.flowers package:

package com.baeldung.componentscan.springapp.flowers;
// ...
@Component
public class Rose {}

The output of the main() method will contain all the beans of com.baeldung.componentscan.springapp package and its sub-packages:

springComponentScanApp
cat
dog
rose
exampleBean

Note that the main application class is also a bean, as it’s annotated with @Configuration, which is a @Component.

We should also note that the main application class and the configuration class are not necessarily the same. If they are different, it doesn’t matter where we put the main application class. Only the location of the configuration class matters, as component scanning starts from its package by default.

Finally, note that in our example, @ComponentScan is equivalent to:

@ComponentScan(basePackages = "com.baeldung.componentscan.springapp")

The basePackages argument is a package or an array of packages for scanning.

2.2. Using @ComponentScan in a Spring Boot Application

The trick with Spring Boot is that many things happen implicitly. We use the @SpringBootApplication annotation, but it’s a combination of three annotations:

@Configuration
@EnableAutoConfiguration
@ComponentScan

Let’s create a similar structure in com.baeldung.componentscan.springbootapp package. This time the main application will be:

package com.baeldung.componentscan.springbootapp;
// ...
@SpringBootApplication
public class SpringBootComponentScanApp {
    private static ApplicationContext applicationContext;

    @Bean
    public ExampleBean exampleBean() {
        return new ExampleBean();
    }

    public static void main(String[] args) {
        applicationContext = SpringApplication.run(SpringBootComponentScanApp.class, args);
        checkBeansPresence(
          "cat", "dog", "rose", "exampleBean", "springBootComponentScanApp");

    }

    private static void checkBeansPresence(String... beans) {
        for (String beanName : beans) {
            System.out.println("Is " + beanName + " in ApplicationContext: " + 
              applicationContext.containsBean(beanName));
        }
    }
}

All other packages and classes remain the same, we’ll just copy them to the nearby com.baeldung.componentscan.springbootapp package.

Spring Boot scans packages similarly to our previous example. Let’s check the output:

Is cat in ApplicationContext: true
Is dog in ApplicationContext: true
Is rose in ApplicationContext: true
Is exampleBean in ApplicationContext: true
Is springBootComponentScanApp in ApplicationContext: true

The reason we’re just checking the beans for existence in our second example (as opposed to printing out all the beans), is that the output would be too large.

This is because of the implicit @EnableAutoConfiguration annotation, which makes Spring Boot create many beans automatically, relying on the dependencies in pom.xml file.

3. @ComponentScan With Arguments

Now let’s customize the paths for scanning. For example, let’s say we want to exclude the Rose bean.

3.1. @ComponentScan for Specific Packages

We can do this a few different ways. First, we can change the base package:

@ComponentScan(basePackages = "com.baeldung.componentscan.springapp.animals")
@Configuration
public class SpringComponentScanApp {
   // ...
}

Now the output will be:

springComponentScanApp
cat
dog
exampleBean

Let’s see what’s behind this:

  • springComponentScanApp is created as it’s a configuration passed as an argument to the AnnotationConfigApplicationContext
  • exampleBean is a bean configured inside the configuration
  • cat and dog are in the specified com.baeldung.componentscan.springapp.animals package

All of the above-listed customizations are applicable in Spring Boot too. We can use @ComponentScan together with @SpringBootApplication and the result will be the same:

@SpringBootApplication
@ComponentScan(basePackages = "com.baeldung.componentscan.springbootapp.animals")

3.2. @ComponentScan with Exclusions

Another way is to use a filter, specifying the pattern for the classes to exclude:

@ComponentScan(excludeFilters = 
  @ComponentScan.Filter(type=FilterType.REGEX,
    pattern="com\\.baeldung\\.componentscan\\.springapp\\.flowers\\..*"))

We can also choose a different filter type, as the annotation supports several flexible options for filtering the scanned classes:

@ComponentScan(excludeFilters = 
  @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Rose.class))

4. The Default Package

We should avoid putting the @Configuration class in the default package (i.e. by not specifying the package at all). If we do, Spring scans all the classes in all jars in a classpath, which causes errors and the application probably doesn’t start.

Leave a Comment