Component Scanning

Component scanning is how Spring automatically discovers classes annotated with @Component (and its specializations) and registers them as beans, with no XML or manual @Bean needed. @SpringBootApplication includes @ComponentScan, which scans the package of the main class and all its sub-packages. It is used so you can just annotate a class and have it become a managed bean, which keeps configuration small and the code organized by package. Classes outside the scanned packages are invisible to Spring unless you widen the scan.

Types

  • Default scan: @SpringBootApplication scans the main class’s package and its sub-packages.
  • Custom scan: @ComponentScan(basePackages = "...") or @SpringBootApplication(scanBasePackages = {...}) adds other packages.
  • Type-safe scan: @ComponentScan(basePackageClasses = SomeClass.class) scans the package of a marker class.
  • Filtered scan: includeFilters and excludeFilters pick or skip classes by annotation, type, or regex.
  • Detected annotations: @Component, @Service, @Repository, @Controller / @RestController, @Configuration.

Hands-on Experiment: Creating a spring boot application along with Component Scanning

The following steps are involved in developing this hands-on experiment.

Step 1: Generate the Project

Step 2: Project Structure

Step 3: pom.xml

Step 4: application.yml

Step 5: Create Entity Class

Step 6: Create Repository Interface

Step 7: Create Service Class

Step 8: Create Controller Class

Step 9: Main Application Class

Step 10: Run the Main Application Class

Step 1: Configure the Project on Spring Initializr

Go to start.spring.io and set:

  • Project: Maven
  • Language: Java
  • Spring Boot version: 3.2.x
  • Group: com.example
  • Artifact: studentscan
  • Name: studentscan
  • Package name: com.example.studentscan
  • Packaging: Jar
  • Java: 17
  • Dependencies: Spring Web, Spring Data JPA, MySQL Driver

Click Generate to download the ZIP, then extract and import it into your IDE as a Maven project.

Step 2: Generated Project Structure

Step 3: Explore pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.5</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>student-scan-simple</artifactId>
    <version>1.0.0</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Step 4: application.yml

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/student_scan_simple_db?createDatabaseIfNotExist=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
    username: root
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
server:
  port: 8082Code language: JavaScript (javascript)

Step 5: Create Entity class

package com.example.studentscan.entity;

import jakarta.persistence.*;

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String course;

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public String getCourse() { return course; }
    public void setCourse(String course) { this.course = course; }
}

Step 6: Create Repository interface

package com.example.studentscan.repository;

import com.example.studentscan.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student, Long> {
}

Step 7: Create Service class

package com.example.studentscan.service;

import com.example.studentscan.entity.Student;
import com.example.studentscan.repository.StudentRepository;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class StudentService {

    private final StudentRepository repository;

    public StudentService(StudentRepository repository) {
        this.repository = repository;
    }

    public Student save(Student student) {
        return repository.save(student);
    }

    public List<Student> findAll() {
        return repository.findAll();
    }

    public Student findById(Long id) {
        return repository.findById(id).orElseThrow(() -> new RuntimeException("Student not found: " + id));
    }
}

Step 8: Create Controller class

package com.example.studentscan.controller;

import com.example.studentscan.entity.Student;
import com.example.studentscan.service.StudentService;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/students")
public class StudentController {

    private final StudentService service;

    public StudentController(StudentService service) {
        this.service = service;
    }

    @PostMapping
    public Student create(@RequestBody Student student) {
        return service.save(student);
    }

    @GetMapping
    public List<Student> getAll() {
        return service.findAll();
    }

    @GetMapping("/{id}")
    public Student getById(@PathVariable Long id) {
        return service.findById(id);
    }
}
package com.example.studentscan.config;

import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import java.util.Arrays;

// A @Component too - found by scanning. Prints every scanned bean at startup.
@Component
public class ScanPrinter implements CommandLineRunner {

    private final ApplicationContext context;

    public ScanPrinter(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public void run(String... args) {
        System.out.println("===== Beans found by component scanning =====");
        Arrays.stream(context.getBeanDefinitionNames())
                .filter(n -> context.getType(n) != null
                        && ClassUtils.getUserClass(context.getType(n)).getName().startsWith("com.example"))
                .sorted()
                .forEach(n -> System.out.println(" -> " + n + "  (" + ClassUtils.getUserClass(context.getType(n)).getPackageName() + ")"));
        System.out.println("=============================================");
    }
}

Step 9: Main Application

package com.example.studentscan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// Scans com.example.studentscan and all sub-packages (controller, service, repository, config)
@SpringBootApplication
public class StudentScanApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentScanApplication.class, args);
    }
}

Step 10: Run the StudentScanApplication

Scroll to Top