Spring 5 InitializingBean and DisposableBean Example

In Spring, to interact with the container’s management of the bean lifecycle, you can implement the Spring InitializingBean and DisposableBean interfaces. The container calls afterPropertiesSet() for the former and destroy() for the latter to let the bean perform certain actions upon initialization and destruction of your beans.
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered best practice for receiving lifecycle callbacks in a modern Spring application. Using these annotations means that your beans are not coupled to Spring-specific interfaces. 
Check out Spring @PostConstruct and @PreDestroy Example
  1. For bean implemented InitializingBean, it will run afterPropertiesSet() after all bean properties have been set.
  2. For bean implemented DisposableBean, it will run destroy() after Spring container is released the bean.
In this article, we use the latest release of Spring 5.1.0.RELEASE version to demonstrate this example.

Spring InitializingBean and DisposableBean Example

In real time projects, we populate a database table with some records during application startup and will delete records from same database table during application shutdown.
In this example, we will populate the in-memory List data structure with few user objects during application startup using afterPropertiesSet() method. We will also delete user objects from List during application shutdown using destroy() method.

Tools and technologies used

  • Spring Framework - 5.1.0.RELEASE
  • JDK - 8 or later
  • Maven - 3.2+
  • IDE - Eclipse Mars/STS

Create a Simple Maven Project

Create a simple maven project using your favorite IDE and refer below section for packaging structure. If you are new to maven then read this article How to Create a Simple Maven Project.

Project Structure

Below diagram shows a project structure for your reference - 

The pom.xml File

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>net.javaguides.spring</groupId>
    <artifactId>spring-bean-lifecycle</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.0.RELEASE</version>
        </dependency>  
    </dependencies>
    <build>
     <sourceDirectory>src/main/java</sourceDirectory>
         <plugins>
            <plugin>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.5.1</version>
               <configuration>
                   <source>1.8</source>
                   <target>1.8</target>
               </configuration>
           </plugin>
         </plugins>
     </build>
</project>
Consider DatabaseInitiaizer class which implements InitializingBean and DisposableBean interfaces.

DatabaseInitiaizer.java

package net.javaguides.spring;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class DatabaseInitiaizer implements InitializingBean, DisposableBean {

    private List < User > listOfUsers = new ArrayList < > ();

    @Override
    public void afterPropertiesSet() throws Exception {
        User user = new User(1, "User");
        User user1 = new User(2, "Admin");
        User user2 = new User(3, "SuperAdmin");

        listOfUsers.add(user);
        listOfUsers.add(user1);
        listOfUsers.add(user2);
        System.out.println("-----------List of users added in init() method ------------");
        for (Iterator < User > iterator = listOfUsers.iterator(); iterator.hasNext();) {
            User user3 = (User) iterator.next();
            System.out.println(user3.toString());
        }
        // save to database
    }

    @Override
    public void destroy() {
        // Delete from database
        listOfUsers.clear();
        System.out.println("-----------After of users removed from List in destroy() method ------------");
        for (Iterator < User > iterator = listOfUsers.iterator(); iterator.hasNext();) {
            User user3 = (User) iterator.next();
            System.out.println(user3.toString());
        }
        System.out.println("List is clean up ..");
    }
}

Create POJO - User.java

package net.javaguides.spring;

public class User {
    private Integer id;
    private String name;

    public User() {}

    public User(Integer id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + "]";
    }
}

Annotation Based Configuration - AppConfig.java

Create AppConfig class and write the following code in it.
package net.javaguides.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = "net.javaguides.spring")
public class AppConfig {
 
}
Note - @ComponentScan annotation scans all beans, whose class is annotated by the @Component annotation in a package, specified by basePackages attribute.

Running Spring Application - Application.java

Let's create a main class and run an application.
package net.javaguides.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        context.close();
    }
}

Output

-----------List of users added in init() method ------------
User [id=1, name=User]
User [id=2, name=Admin]
User [id=3, name=SuperAdmin]
-----------After of users removed from List in destroy() method -------
List is clean up ..
The JSR-250 @PostConstruct and @PreDestroy annotations are generally considered best practice for receiving lifecycle callbacks in a modern Spring application. Using these annotations means that your beans are not coupled to Spring-specific interfaces. For details, see Using @PostConstruct and @PreDestroy.
The source code of this example is available on my GitHub repository https://github.com/RameshMF/spring-core-tutorial

Reference

Comments