Component Scanning and Bean Lifecycle in Spring Boot


Table of Contents

  1. Introduction to Component Scanning
  2. Default Component Scanning Behavior
  3. Customizing Component Scanning
  4. Spring Bean Lifecycle Overview
  5. Bean Initialization and Destruction
  6. Bean Lifecycle Hooks: @PostConstruct and @PreDestroy
  7. Using InitializingBean and DisposableBean Interfaces
  8. Using @Bean with initMethod and destroyMethod
  9. Lifecycle Annotations vs Interfaces
  10. Best Practices
  11. Conclusion

1. Introduction to Component Scanning

Spring Boot uses Component Scanning to automatically detect and register beans (classes) into the application context based on annotations. This mechanism reduces boilerplate configuration and allows Spring to manage your classes as beans without explicit XML or Java-based registration.


2. Default Component Scanning Behavior

By default, Spring Boot scans for components (like @Component, @Service, @Repository, and @Controller) in the same package as the main application class and its sub-packages.

Example:

javaCopyEdit@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

If MyApp is in the package com.example, Spring will scan com.example and all its sub-packages automatically.


3. Customizing Component Scanning

To scan additional packages or control scanning behavior, use @ComponentScan:

javaCopyEdit@SpringBootApplication
@ComponentScan(basePackages = {"com.example.services", "com.example.controllers"})
public class MyApp { }

You can also exclude or include components based on annotations or custom filters:

javaCopyEdit@ComponentScan(
    basePackages = "com.example",
    excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Deprecated.class)
)

4. Spring Bean Lifecycle Overview

A Spring Bean is an object managed by the Spring IoC (Inversion of Control) container. The lifecycle of a bean includes:

  • Instantiation
  • Dependency Injection (Population)
  • Custom Initialization
  • Usage
  • Custom Destruction

5. Bean Initialization and Destruction

Spring provides multiple ways to hook into the bean lifecycle:

  • Annotation-based (@PostConstruct, @PreDestroy)
  • Interface-based (InitializingBean, DisposableBean)
  • XML-based (not commonly used in Spring Boot)
  • Java config using @Bean(initMethod, destroyMethod)

6. Bean Lifecycle Hooks: @PostConstruct and @PreDestroy

These annotations are used on methods that should run after dependency injection and before bean destruction:

javaCopyEdit@Component
public class MyService {

    @PostConstruct
    public void init() {
        System.out.println("Bean is going through init.");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Bean will be destroyed.");
    }
}

Requirements:

  • Must be void
  • No parameters
  • Only one method per annotation

7. Using InitializingBean and DisposableBean Interfaces

These are older but still valid ways to handle lifecycle events:

javaCopyEdit@Component
public class MyService implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: afterPropertiesSet called.");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: destroy called.");
    }
}

These are interface-based, which may reduce flexibility compared to annotations.


8. Using @Bean with initMethod and destroyMethod

If you’re using Java-based configuration and defining beans with @Bean, you can specify lifecycle methods directly:

javaCopyEdit@Configuration
public class AppConfig {

    @Bean(initMethod = "init", destroyMethod = "cleanup")
    public MyBean myBean() {
        return new MyBean();
    }
}

Inside MyBean:

javaCopyEditpublic class MyBean {
    public void init() {
        System.out.println("Init method called.");
    }

    public void cleanup() {
        System.out.println("Destroy method called.");
    }
}

9. Lifecycle Annotations vs Interfaces

Feature@PostConstruct/@PreDestroyInitializingBean/DisposableBean
StyleDeclarative (Annotation)Programmatic (Interface)
Preferred in Spring Boot✅ Yes❌ Less preferred
Testable✅ Better⚠️ Coupled to Spring API
Flexibility✅ High⚠️ Low (must implement interfaces)

10. Best Practices

  • Use @PostConstruct and @PreDestroy for cleaner code and better decoupling.
  • Avoid field injection and prefer constructor injection for lifecycle-safe design.
  • Minimize bean lifecycle logic and move business logic into proper service layers.
  • Use @ComponentScan sparingly to avoid unnecessarily loading unwanted components.

11. Conclusion

Understanding Component Scanning and the Bean Lifecycle is essential when working with Spring Boot. These concepts ensure that your application is both modular and maintainable, while taking full advantage of Spring’s powerful dependency injection and lifecycle management capabilities.