DEV Community

Hunor Vadasz-Perhat
Hunor Vadasz-Perhat

Posted on

spring-012: entire-spring-bean-lifecycle-from-registration-to-destruction-with-sample-examples

Here I systematically explore Spring's lifecycle methods by implementing them one by one in a structured way πŸš€


Step 1: Understanding registerBeanDefinition() in Practice

We are starting with how Spring registers bean definitions before instantiation using BeanDefinitionRegistry.


πŸ”Ή What Happens at This Stage?

  • Spring loads and registers bean definitions from:
    • @ComponentScan
    • @Bean methods inside @Configuration
    • XML-based configuration (if used)
  • At this point, no beans are instantiated yet! Spring is just storing the metadata about each bean.

πŸ”Ή Practical Example: Registering a Bean Manually

  1. We define a class CustomBeanRegistrar that implements BeanDefinitionRegistryPostProcessor.
  2. Inside postProcessBeanDefinitionRegistry(), we register a bean definition manually.
  3. We create a bean class (MyDynamicBean) that will be instantiated when accessed.
@Configuration
public class CustomBeanRegistrar implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // Define a new bean manually
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(MyDynamicBean.class);
        registry.registerBeanDefinition("myDynamicBean", beanDefinition);
        System.out.println("Custom bean definition registered: MyDynamicBean");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // Not needed for this example
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή Key Takeaways

βœ… This method is used to dynamically register beans (e.g., based on conditions, external configs).

βœ… At this stage, beans are just "blueprints"β€”actual instances are not created yet.

βœ… Best Practice: Only use this when dynamic bean registration is needed (e.g., custom plugins).


Step 2: Understanding postProcessBeforeInstantiation()

Now that we've covered bean definition registration, the next lifecycle method is InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation().


πŸ”Ή What Happens at This Stage?

  • This method runs before the actual instantiation of a bean.
  • It allows you to:
    • Modify or replace the bean instance before it is created.
    • Prevent normal instantiation by returning a proxy or a custom instance.

πŸ”Ή Practical Example: Intercepting Bean Instantiation

We've implemented InstantiationAwareBeanPostProcessor to log when this method is called.

@Component
class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("Before instantiating bean: " + beanName);
        return null; // Returning null allows normal instantiation
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… This method executes before the constructor is called.

βœ… You can return a different instance instead of allowing the default instantiation.

βœ… Best Practice: Use it for AOP (Aspect-Oriented Programming) scenarios like creating proxies.


Step 3: Understanding setBeanName()

Now that we've covered postProcessBeforeInstantiation(), the next lifecycle method is BeanNameAware#setBeanName().


πŸ”Ή What Happens at This Stage?

  • After the bean is instantiated, Spring calls setBeanName().
  • This allows the bean to know its own name in the application context.
  • This happens before dependency injection.

πŸ”Ή Practical Example: Bean Recognizing Its Own Name

We've extended the existing application to include BeanNameAware inside MyDynamicBean:

class MyDynamicBean implements BeanNameAware {
    private String beanName;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The method is called immediately after instantiation.

βœ… The bean can store its own name for later use.

βœ… Best Practice: Use this when the bean needs to log or manipulate its own name.


Step 4: Understanding setBeanClassLoader()

Now that we've covered setBeanName(), the next lifecycle method is BeanClassLoaderAware#setBeanClassLoader().


πŸ”Ή What Happens at This Stage?

  • After setting the bean name, Spring calls setBeanClassLoader(ClassLoader classLoader).
  • This method allows the bean to access the ClassLoader that loaded it.
  • The ClassLoader is responsible for loading classes into memory.

πŸ”Ή Practical Example: Accessing Bean ClassLoader

We've extended our MyDynamicBean class to implement BeanClassLoaderAware:

class MyDynamicBean implements BeanNameAware, BeanClassLoaderAware {
    private String beanName;
    private ClassLoader classLoader;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        System.out.println("Bean ClassLoader set: " + classLoader);
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setBeanClassLoader() method is called after setBeanName().

βœ… The ClassLoader allows the bean to dynamically load classes at runtime.

βœ… Best Practice: Use it when you need to load classes dynamically (e.g., plugins, external dependencies).


Step 5: Understanding setBeanFactory()

Now that we've covered setBeanClassLoader(), the next lifecycle method is BeanFactoryAware#setBeanFactory().


πŸ”Ή What Happens at This Stage?

  • After setting the bean name and class loader, Spring calls setBeanFactory().
  • This method provides access to the BeanFactory, which is the core Spring container that holds all bean instances.
  • The bean can now programmatically retrieve other beans from the factory.

πŸ”Ή Practical Example: Accessing the BeanFactory

We've extended MyDynamicBean to implement BeanFactoryAware:

class MyDynamicBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {
    private String beanName;
    private ClassLoader classLoader;
    private BeanFactory beanFactory;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        System.out.println("Bean ClassLoader set: " + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactory set: " + beanFactory);
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setBeanFactory() method is called after setBeanClassLoader().

βœ… The BeanFactory allows beans to retrieve other beans programmatically.

βœ… Best Practice: Use dependency injection (@Autowired) instead of directly accessing BeanFactory, unless you need dynamic lookups.


Step 6: Understanding setEnvironment()

Now that we've covered setBeanFactory(), the next lifecycle method is EnvironmentAware#setEnvironment().


πŸ”Ή What Happens at This Stage?

  • After setting bean factory access, Spring calls setEnvironment().
  • This method allows the bean to access environment properties, such as:
    • System properties (System.getProperty("key"))
    • Application properties (application.properties / application.yml)
    • Profiles (spring.profiles.active)
    • Other configurable settings.

πŸ”Ή Practical Example: Accessing Environment Variables

We've extended MyDynamicBean to implement EnvironmentAware:

class MyDynamicBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware {
    private String beanName;
    private ClassLoader classLoader;
    private BeanFactory beanFactory;
    private Environment environment;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        System.out.println("Bean ClassLoader set: " + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactory set: " + beanFactory);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        System.out.println("Environment set: " + environment);
        System.out.println("Active Profile: " + environment.getActiveProfiles());
        System.out.println("Server Port: " + environment.getProperty("server.port"));
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setEnvironment() method is called after setBeanFactory().

βœ… The environment allows access to application properties and profiles.

βœ… Best Practice: Use it when a bean needs to read environment properties dynamically.


Step 7: Understanding setEmbeddedValueResolver()

Now that we've covered setEnvironment(), the next lifecycle method is EmbeddedValueResolverAware#setEmbeddedValueResolver().


πŸ”Ή What Happens at This Stage?

  • After setting environment access, Spring calls setEmbeddedValueResolver().
  • This method provides a StringValueResolver that allows resolving embedded placeholders (e.g., ${server.port} or #{expression}).
  • Useful when dealing with property placeholders or Spring Expression Language (SpEL).

πŸ”Ή Practical Example: Resolving Embedded Placeholders

We've extended MyDynamicBean to implement EmbeddedValueResolverAware:

class MyDynamicBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware {
    private String beanName;
    private ClassLoader classLoader;
    private BeanFactory beanFactory;
    private Environment environment;
    private StringValueResolver valueResolver;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        System.out.println("Bean ClassLoader set: " + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactory set: " + beanFactory);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        System.out.println("Environment set: " + environment);
        System.out.println("Active Profile: " + environment.getActiveProfiles());
        System.out.println("Server Port: " + environment.getProperty("server.port"));
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        String resolvedValue = valueResolver.resolveStringValue("${server.port}");
        System.out.println("Embedded Value Resolved: " + resolvedValue);
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setEmbeddedValueResolver() method is called after setEnvironment().

βœ… Allows resolving placeholders like ${property.name} dynamically.

βœ… Best Practice: Use this when a bean needs to dynamically resolve properties or SpEL expressions.


Step 8: Understanding setResourceLoader()

Now that we've covered setEmbeddedValueResolver(), the next lifecycle method is ResourceLoaderAware#setResourceLoader().


πŸ”Ή What Happens at This Stage?

  • After setting the embedded value resolver, Spring calls setResourceLoader().
  • This method provides a ResourceLoader, which allows loading external resources such as:
    • Files from the classpath (classpath:/config.xml)
    • Files from the file system (file:/tmp/config.xml)
    • URLs (https://example.com/config.xml)

πŸ”Ή Practical Example: Accessing Resources

We've extended MyDynamicBean to implement ResourceLoaderAware:

class MyDynamicBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware {
    private String beanName;
    private ClassLoader classLoader;
    private BeanFactory beanFactory;
    private Environment environment;
    private StringValueResolver valueResolver;
    private ResourceLoader resourceLoader;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        System.out.println("Bean ClassLoader set: " + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactory set: " + beanFactory);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        System.out.println("Environment set: " + environment);
        System.out.println("Active Profile: " + environment.getActiveProfiles());
        System.out.println("Server Port: " + environment.getProperty("server.port"));
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        String resolvedValue = valueResolver.resolveStringValue("${server.port}");
        System.out.println("Embedded Value Resolved: " + resolvedValue);
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
        System.out.println("ResourceLoader set: " + resourceLoader);

        // Example usage: Load a file from classpath
        System.out.println("Loading resource example: " + resourceLoader.getResource("classpath:application.properties").exists());
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setResourceLoader() method is called after setEmbeddedValueResolver().

βœ… The ResourceLoader allows loading external files dynamically.

βœ… Best Practice: Use ResourceLoader when a bean needs to load external configurations or static assets.


Step 9: Understanding setApplicationEventPublisher()

Now that we've covered setResourceLoader(), the next lifecycle method is ApplicationEventPublisherAware#setApplicationEventPublisher().


πŸ”Ή What Happens at This Stage?

  • After setting the resource loader, Spring calls setApplicationEventPublisher().
  • This method provides an ApplicationEventPublisher, which allows the bean to:
    • Publish custom application events.
    • Trigger event-driven components (such as @EventListener).

πŸ”Ή Practical Example: Publishing an Event

We've extended MyDynamicBean to implement ApplicationEventPublisherAware:

class MyDynamicBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware {
    private String beanName;
    private ClassLoader classLoader;
    private BeanFactory beanFactory;
    private Environment environment;
    private StringValueResolver valueResolver;
    private ResourceLoader resourceLoader;
    private ApplicationEventPublisher eventPublisher;

    public MyDynamicBean() {
        System.out.println("MyDynamicBean instantiated!");
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("Bean name set: " + name);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
        System.out.println("Bean ClassLoader set: " + classLoader);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactory set: " + beanFactory);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
        System.out.println("Environment set: " + environment);
        System.out.println("Active Profile: " + environment.getActiveProfiles());
        System.out.println("Server Port: " + environment.getProperty("server.port"));
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.valueResolver = resolver;
        String resolvedValue = valueResolver.resolveStringValue("${server.port}");
        System.out.println("Embedded Value Resolved: " + resolvedValue);
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
        System.out.println("ResourceLoader set: " + resourceLoader);
        System.out.println("Loading resource example: " + resourceLoader.getResource("classpath:application.properties").exists());
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
        System.out.println("ApplicationEventPublisher set: " + eventPublisher);

        // Publish a custom event
        eventPublisher.publishEvent(new CustomEvent(this, "Test Event Message"));
    }
}

// Custom Event Class
class CustomEvent extends org.springframework.context.ApplicationEvent {
    private final String message;

    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

// Listener for Custom Events
@Component
class CustomEventListener {
    @org.springframework.context.event.EventListener
    public void handleCustomEvent(CustomEvent event) {
        System.out.println("Received Custom Event: " + event.getMessage());
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setApplicationEventPublisher() method is called after setResourceLoader().

βœ… The ApplicationEventPublisher allows beans to trigger application events.

βœ… Best Practice: Use ApplicationEventPublisher for decoupling components via event-driven programming.


Step 10: Understanding setMessageSource()

Now that we've covered setApplicationEventPublisher(), the next lifecycle method is MessageSourceAware#setMessageSource().


πŸ”Ή What Happens at This Stage?

  • After setting the ApplicationEventPublisher, Spring calls setMessageSource().
  • This method provides a MessageSource, which allows beans to:
    • Retrieve localized messages (for internationalization).
    • Access messages.properties files for text translations.

πŸ”Ή Practical Example: Retrieving Messages

We've extended MyDynamicBean to implement MessageSourceAware:

@Override
public void setMessageSource(MessageSource messageSource) {
    this.messageSource = messageSource;
    System.out.println("MessageSource set: " + messageSource);

    // Retrieve a message from messages.properties (if configured)
    System.out.println("Example message: " + messageSource.getMessage("example.message", null, "Default Message", null));
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setMessageSource() method is called after setApplicationEventPublisher().

βœ… MessageSource allows retrieving localized messages dynamically.

βœ… Best Practice: Use MessageSource for internationalization and text localization.


Step 11: Understanding setApplicationContext()

Now that we've covered setMessageSource(), the next lifecycle method is ApplicationContextAware#setApplicationContext().


πŸ”Ή What Happens at This Stage?

  • After setting the MessageSource, Spring calls setApplicationContext().
  • This method provides an ApplicationContext, which allows beans to:
    • Access all beans in the Spring container.
    • Retrieve environment properties.
    • Interact with the lifecycle of the entire application.

πŸ”Ή Practical Example: Accessing the ApplicationContext

We've extended MyDynamicBean to implement ApplicationContextAware:

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
    System.out.println("ApplicationContext set: " + applicationContext);

    // Example: Retrieving a bean dynamically
    MyDynamicBean anotherBean = applicationContext.getBean(MyDynamicBean.class);
    System.out.println("Retrieved bean from ApplicationContext: " + anotherBean);
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setApplicationContext() method is called after setMessageSource().

βœ… ApplicationContext provides access to all registered beans dynamically.

βœ… Best Practice: Use @Autowired instead of manually accessing the ApplicationContext, unless necessary.


Step 12: Understanding setServletContext()

Now that we've covered setApplicationContext(), the next lifecycle method is ServletContextAware#setServletContext() (applicable for web applications).


πŸ”Ή What Happens at This Stage?

  • After setting the ApplicationContext, Spring calls setServletContext().
  • This method provides access to the ServletContext, allowing the bean to:
    • Interact with web-related resources.
    • Retrieve application-wide configuration parameters.
    • Access web-related objects like request/session attributes.

πŸ”Ή Practical Example: Accessing the ServletContext

We've extended MyDynamicBean to implement ServletContextAware:

@Override
public void setServletContext(ServletContext servletContext) {
    this.servletContext = servletContext;
    System.out.println("ServletContext set: " + servletContext);

    // Example: Retrieving a context parameter
    String contextParam = servletContext.getInitParameter("someConfig");
    System.out.println("Context Parameter: " + contextParam);
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The setServletContext() method is called after setApplicationContext().

βœ… ServletContext allows interaction with web-specific components.

βœ… Best Practice: Use ServletContext only when necessary; prefer Spring beans for managing web configurations.


Step 13: Understanding postProcessBeforeInitialization()

Now that we've covered setServletContext(), the next lifecycle method is BeanPostProcessor#postProcessBeforeInitialization().


πŸ”Ή What Happens at This Stage?

  • Spring calls postProcessBeforeInitialization() before the initialization callbacks (@PostConstruct, InitializingBean#afterPropertiesSet()).
  • This method allows beans to:
    • Modify bean properties before initialization.
    • Apply proxying, validation, or logging before initialization.

πŸ”Ή Practical Example: Intercepting Bean Initialization

We've added a BeanPostProcessor to modify beans before initialization:

@Component
class CustomBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization called for: " + beanName);
        return bean;
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The postProcessBeforeInitialization() method is called before @PostConstruct and afterPropertiesSet().

βœ… Best Practice: Use this for bean modifications, logging, or applying custom initialization logic.


Step 14: Understanding @PostConstruct and afterPropertiesSet()

Now that we've covered postProcessBeforeInitialization(), the next lifecycle methods are @PostConstruct and InitializingBean#afterPropertiesSet().


πŸ”Ή What Happens at This Stage?

  • Spring calls initialization callbacks after postProcessBeforeInitialization(), including:
    • @PostConstruct: A method annotated with @PostConstruct runs after dependency injection is completed.
    • afterPropertiesSet(): This method is part of the InitializingBean interface and runs after all properties are set.
  • These methods are typically used for:
    • Validating required properties.
    • Setting up resources after dependency injection.

πŸ”Ή Practical Example: Using @PostConstruct and afterPropertiesSet()

We've modified MyDynamicBean to implement InitializingBean and added a @PostConstruct method:

@PostConstruct
public void postConstruct() {
    System.out.println("@PostConstruct method executed");
}

@Override
public void afterPropertiesSet() throws Exception {
    System.out.println("afterPropertiesSet() method executed");
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… @PostConstruct runs before afterPropertiesSet().

βœ… Best Practice: Use @PostConstruct for setup logic, and afterPropertiesSet() when implementing InitializingBean.

βœ… Avoid implementing InitializingBean unless absolutely necessary, as @PostConstruct is more flexible.


Step 15: Understanding postProcessAfterInitialization()

Now that we've covered @PostConstruct and afterPropertiesSet(), the next lifecycle method is BeanPostProcessor#postProcessAfterInitialization().


πŸ”Ή What Happens at This Stage?

  • Spring calls postProcessAfterInitialization() after initialization callbacks (@PostConstruct, afterPropertiesSet()).
  • This method allows:
    • Applying proxying mechanisms (e.g., AOP).
    • Performing post-initialization modifications (e.g., wrapping the bean).

πŸ”Ή Practical Example: Intercepting Bean Post-Initialization

We've extended CustomBeanPostProcessor to implement postProcessAfterInitialization():

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessAfterInitialization called for: " + beanName);
    return bean;
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… The postProcessAfterInitialization() method is called after @PostConstruct and afterPropertiesSet().

βœ… Best Practice: Use this method for applying proxies or final modifications after the bean is fully initialized.


Step 16: Understanding @PreDestroy and destroy()

Now that we've covered postProcessAfterInitialization(), the final lifecycle methods are @PreDestroy and DisposableBean#destroy().


πŸ”Ή What Happens at This Stage?

  • Spring calls destruction callbacks before shutting down the application.
  • These methods ensure proper resource cleanup:
    • @PreDestroy: Runs before the bean is destroyed, ideal for closing resources.
    • destroy(): From DisposableBean, allows executing destruction logic.

πŸ”Ή Practical Example: Cleaning Up Resources

We've modified MyDynamicBean to implement DisposableBean and added a @PreDestroy method:

@PreDestroy
public void preDestroy() {
    System.out.println("@PreDestroy method executed");
}

@Override
public void destroy() throws Exception {
    System.out.println("destroy() method executed");
}
Enter fullscreen mode Exit fullscreen mode

πŸ’‘ Key Observations

βœ… @PreDestroy runs before destroy().

βœ… Best Practice: Use @PreDestroy for graceful shutdown and destroy() if implementing DisposableBean.

βœ… Avoid implementing DisposableBean unless required, as @PreDestroy is more flexible.


Happy coding πŸš€

Top comments (0)