Open In App

Spring – init() and destroy() Methods with Example

Improve
Improve
Like Article
Like
Save
Share
Report

During the Spring Application Development, sometimes when the spring beans are created developers are required to execute the initialization operations and the cleanup operations before the bean is destroyed. In the spring framework, we can use the init-method and the destroy-method labels in the bean configuration. 

init() Method

In the real-world application init() method is the one you will find it everywhere. init-method is the attribute of the spring <bean> tag. It is utilized to declare a custom method for the bean that will act as the bean initialization method. We can define it as follows.

<bean id="student" class="com.amiya.Student" init-method="myPostConstruct">

Here myPostConstruct() method is the bean initialization method in the Student class. This initialization method is called after initializing bean properties. We can use such an initialization method to validate the value of bean properties or initialize any task. The InitializingBean interface in spring performs the same task but it is highly coupled to spring, so we should prefer the init-method.

Why init()?

  • You can add custom code/logic during bean initialization
  • It can be used for setting up resources like database/socket/file etc.

destroy() Method

The destroy() method will be called before the bean is removed from the container. destroy-method is bean attribute using which we can assign a custom bean method that will be called just before the bean is destroyed. To use the destroy-method attribute, we do as follows.

<bean id="student" class="com.amiya.Student" destroy-method="myPreDestroy">

Here myPreDestroy() method will be defined in the Student class. Spring will call this method just before destroying the bean. destroy-method is used to release resources or perform some destruction task. DisposableBean interface in spring performs the same task but it is highly coupled to spring, so we should prefer destroy-method. So let’s understand these two methods with a simple example. 

Tip: It is good to go with JDBC Tutorial prior because it serves as a pre-requisite.

Implementation:

We are going to explain init() and destroy() Methods through @PostConstruct and @PreDestroy Annotation by simply creating a Spring JDBC project. So let’s create a Spring JDBC project first. 

Step 1: Create a simple Java project in your preferred IDE (IntelliJ IDEA or Eclipse). 

Tip: You can refer to below listed set of articles as follows:

Step 2: Create some tables inside your database. In this article, we have used the MySQL database. And the following data has been present inside our MySQL Database

Data Inside our MySQL Database

So here studentdb is our schema name and hostelstudentinfo is the table name. Similarly, you can create your own schema and table and put some data inside that table manually. 

Tip: You can refer to below listed set of articles as follows:

Step 3: Go to the Java project and create one class named StudentDAO and inside the class, we are going to create a single method selectAllRows() to fetch all the data present inside our MySQL database. We are also going to declare our four most important attributes to connect our Java program with the MySQL server listed below as follows: 

  1. Driver
  2. URL
  3. User
  4. Password

Example

Java




// Java Program to Illustrate StudentDAO Class
  
// Importing required classes
import java.sql.*;
  
// Class
public class StudentDAO {
  
    // Class data members
    private String driver;
    private String url;
    private String userName;
    private String password;
  
    // Setter methods for
    // Setter Injection
    public void setDriver(String driver)
    {
  
        // This keyword refers to current instance itself
        this.driver = driver;
    }
  
    // Setter  
    public void setUrl(String url) { this.url = url; }
  
    // Setter
    public void setUserName(String userName)
    {
        this.userName = userName;
    }
  
    // Setter
    public void setPassword(String password)
    {
        this.password = password;
    }
  
    // Method
    // To select all rows
    public void selectAllRows()
        throws ClassNotFoundException, SQLException
    {
        System.out.println("Retrieving all student data..");
  
        // Loading drivers
        // using forName() method
        Class.forName(driver);
  
        // Getting a connection
        Connection con = DriverManager.getConnection(
            url, userName, password);
  
        // Executing a query
        Statement stmt = con.createStatement();
  
        // Storing it in a ResultSet 
        ResultSet rs = stmt.executeQuery(
            "SELECT * FROM studentdb.hostelstudentinfo");
  
        while (rs.next()) {
            int studentId = rs.getInt(1);
            String studentName = rs.getString(2);
            double hostelFees = rs.getDouble(3);
            String foodType = rs.getString(4);
  
            System.out.println(studentId + " " + studentName
                               + " " + hostelFees + " "
                               + foodType);
        }
  
        // Closing the connection
        // using close() method
        con.close();
    }
}


Step 4: Now we have to Add the External JAR Files to an IntelliJ IDEA Project. A JAR (Java Archive) is a package file format typically used to aggregate many Java class files and associated metadata and resources (text, images, etc.) into one file to distribute application software or libraries on the Java platform. In simple words, a JAR file is a file that contains a compressed version of .class files, audio files, image files, or directories. We have to add the following external jar files to our Java project

  • Spring
  • MySQL Connector

Tip: You can refer to the listed article: How to Add External JAR File to an IntelliJ IDEA Project for which user may download the jar file from the links provided below as follows:

Step 5: Let’s create the bean of StudentDAO class inside the beans.xml file and inject the values of the properties by setter injection. 

Tip: You can refer to the listed article: Spring – Injecting Literal Values By Setter Injection

File: beans.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  
    <bean id="studentDAO" class="StudentDAO">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/studentdb"/>
        <property name="userName" value="root"/>
        <property name="password" value="your password"/>
    </bean>
  
</beans>


Step 6: Create the Main class and let’s test our application is running fine or not. 

File: Main.java

Java




import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
  
import java.sql.SQLException;
  
public class Main {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        
        // Using ApplicationContext tom implement Spring IoC
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        
        // Get the bean studentDAO
        StudentDAO studentDAO = context.getBean("studentDAO", StudentDAO.class);
        
        // Calling the method
        studentDAO.selectAllRows();
    }
}


Output:

One can see we have successfully fetched the data from the MySQL Database.

Retrieving all student data..
1 Asish 300.5 Veg
2 Vicky 245.89 Non Veg
3 Anshul 123.67 Veg

So what’s the problem with the above code? The problem is, suppose we want to define another method deleteStudentRecord(int studentId) in the StudentDAO class something like as represented in below code chunk as follows:

File: StudentDAO Class

public void deleteStudentRecord(int studentId)
throws ClassNotFoundException, SQLException 
{

        // Display command only
        System.out.println("Deleting student data..");

        // Loading driver
        // using forname() method
        Class.forName(driver);

        // Getting a connection
        Connection con = DriverManager.getConnection(url, userName, password);

        // Executing a query
        Statement stmt = con.createStatement();
        stmt.executeUpdate("delete from studentdb.hostelstudentinfo where Student_id = " + studentId);

        // Printing the deleted record to corresponding ID
        System.out.println("Record Deleted with the ID " + studentId);

        // Close the connection
        // using close() method
        con.close();
}

Now you can see we have to write some lines of code again and again. Then think if suppose we want to perform 100 different operations we have to write the same code again and again. So what we can do. We can write the common code inside a method and we can invoke the method. We can write something like this inside a method named createStudentDBConnection()

public void createStudentDBConnection()
throws ClassNotFoundException, SQLException 
{

        // Loading driver
        // using forName() method
        Class.forName(driver);

        // Getting connection
        // using DriverManager
        con = DriverManager.getConnection(url, userName, password);

        // Executing query
        stmt = con.createStatement();
}

Similarly, we can also define another method to close the connection. We can write something like this inside a method named closeConnection()

public void closeConnection() throws SQLException 
{
        con.close();
}

And we can invoke those methods inside the selectAllRows() and deleteStudentRecord() something like this. Now the complete code for the StudentDAO.java class can be written as

File: StudentDAO.java

Java




// Java Program to Illustrate StudentDAO Class
  
// Importing required classes
import java.sql.*;
  
// Class
public class StudentDAO {
  
    // Class data members
    private String driver;
    private String url;
    private String userName;
    private String password;
  
    // Connection Object
    Connection con;
  
    // Statement Object
    Statement stmt;
  
    // Setter
    public void setDriver(String driver)
    {
        this.driver = driver;
    }
  
    // Setter
    public void setUrl(String url) { this.url = url; }
  
    // Setter
    public void setUserName(String userName)
    {
        this.userName = userName;
    }
  
    // Setter
    public void setPassword(String password)
    {
        this.password = password;
    }
  
    // Method
    // Create connection
    public void createStudentDBConnection()
        throws ClassNotFoundException, SQLException
    {
  
        // Loading driver using forName() method
        Class.forName(driver);
  
        // Getting a connection
        con = DriverManager.getConnection(url, userName,
                                          password);
  
        // Executing a query
        stmt = con.createStatement();
    }
  
    // Method
    // To select all rows
    public void selectAllRows()
        throws ClassNotFoundException, SQLException
    {
  
        // Display message
        System.out.println("Retrieving all student data..");
  
        // Create connection
        createStudentDBConnection();
  
        // Storing it in a ResultSet
        ResultSet rs = stmt.executeQuery(
            "SELECT * FROM studentdb.hostelstudentinfo");
  
        while (rs.next()) {
            int studentId = rs.getInt(1);
            String studentName = rs.getString(2);
            double hostelFees = rs.getDouble(3);
            String foodType = rs.getString(4);
  
            // Printing student attributes
            System.out.println(studentId + " " + studentName
                               + " " + hostelFees + " "
                               + foodType);
        }
  
        // Closing connection
        closeConnection()
    }
  
    // Method
    public void deleteStudentRecord(int studentId)
        throws ClassNotFoundException, SQLException
    {
        System.out.println("Deleting student data..");
  
        // Create connection
        createStudentDBConnection();
  
        stmt.executeUpdate(
            "delete from studentdb.hostelstudentinfo where Student_id = "
            + studentId);
        System.out.println("Record Deleted with the ID "
                           + studentId);
  
        // Close the connection
        closeConnection();
    }
  
    // Method
    // Close the connection
    public void closeConnection() throws SQLException
    {
        con.close();
    }
}


But we are doing the same thing again. We are calling the createStudentDBConnection() and closeConnection() method again and again inside the selectAllRows() and deleteStudentRecord() methods. Suppose we have a total of 100 utility methods like that then we have to call these methods 100 times. So we will tell our spring framework that once you (spring framework) create the bean please execute the createStudentDBConnection() method. So the way we are going to tell the spring framework is by putting the @PostConstruct annotation. In summary, we can tell that hey Spring, once you create the StudentDAO object please create createStudentDBConnection() by yourself. Don’t wait for us to call it. 

Spring @PostConstruct Annotation: So generally, whenever we annotate a method in Spring Bean with @PostConstruct annotation, it gets executed after the spring bean is initialized. We can have only one method annotated with @PostConstruct annotation. This annotation is part of Common Annotations API and it’s part of JDK module javax.annotation-api

Note: Adding @PostConstruct and @PreDestroy Annotation in the Project

Developers, who are using Java 9+, both @PostConstruct and @PreDestroy annotations are part of Java EE. And since Java EE has been deprecated in Java 9 and removed in Java 11 we have to add an additional dependency to use these annotations:

If one is using Maven, then   

<dependency>
   <groupId>javax.annotation</groupId>
   <artifactId>javax.annotation-api</artifactId>
   <version>1.3.2</version>
</dependency>

Else, if you add the jar manually, it is as follows:

  • Visit the link and inside the files column, one can see pom and jar.
  • Click on the jar and your jar will be downloaded.
  • Add it to the classpath as an external jar by configuring the build.

One can refer to this article: Add External JAR File to an IntelliJ IDEA Project or refer article: Add External JAR File to an Eclipse Project.

Note: If you are on Java 8 or the lower version, then you won’t have to perform the above stuff.

So now we can put the @PostConstruct Annotation before the createStudentDBConnection() something like this

@PostConstruct
public void createStudentDBConnection()
    throws ClassNotFoundException, SQLException
{

    // Loading driver
    Class.forName(driver);

    // Getting a connection
    con = DriverManager.getConnection(url, userName,
                                      password);

    // Executing query
    stmt = con.createStatement();
}

Introducing init()

In the real-world application init() method is the one you will find it everywhere. We can also say the init() method is a standard name. For example, in this project, we can mark the createStudentDBConnection() method as init. Here the createStudentDBConnection() is the init() method for us. Annotate a method with @PostConstruct to use it as a init() method. We don’t need to call the init() method, our framework will call it for us. We can give our init() method name as anything. We may say it init() or we may say it createStudentDBConnection() or xyz(). So now we can write the same thing like that

@PostConstruct
public void init() throws SQLException, ClassNotFoundException 
{
        createStudentDBConnection();
}

// Method
public void createStudentDBConnection() throws ClassNotFoundException, SQLException 
{

        // Loading driver
        Class.forName(driver);

        // Getting a connection
        con = DriverManager.getConnection(url, userName, password);

        // Executing query
        stmt = con.createStatement();
}

Why init()?

  • You can add custom code/logic during bean initialization
  • It can be used for setting up resources like database/socket/file etc.

Introducing destroy()

The destroy() method will be called before the bean is removed from the container. Now let’s coming to the closeConnection() method. We defined this method for cleaning up unused references. For example in this project the con variable. So we can make any method as destroy() method by marking it as @PreDestroy. So now we can write the code fragment will look like as follows:

// Method
public void closeConnection() throws SQLException
{
    con.close();
}

// Annotation
@PreDestroy
// Method
public void destroy() throws SQLException
{
    closeConnection();
}

Spring @PreDestroy Annotation: When we annotate a Spring Bean method with PreDestroy annotation, it gets called when the bean instance is getting removed from the context. Remember that if your spring bean scope is “prototype” then it’s not completely managed by the spring container and the PreDestroy method won’t get called. If there is a method named shutdown or close then the spring container will try to automatically configure them as callback methods when the bean is being destroyed.

Note that we can also use the @PreDestroy annotation before the closeConnection() method.

File: StudentDAO.java

Java




// Java Program to Illustrate StudentDAO Class
  
// Importing required classes
import java.sql.*;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
  
// Class
public class StudentDAO {
  
    // Class data members
    private String driver;
    private String url;
    private String userName;
    private String password;
  
    // Connection Object
    Connection con;
  
    // Statement Object
    Statement stmt;
  
    // Setter
    public void setDriver(String driver)
    {
        this.driver = driver;
    }
  
    // Setter
    public void setUrl(String url) { this.url = url; }
  
    // Setter
    public void setUserName(String userName)
    {
        this.userName = userName;
    }
  
    // Setter
    public void setPassword(String password)
    {
        this.password = password;
    }
  
    @PostConstruct
    public void init()
        throws SQLException, ClassNotFoundException
    {
        createStudentDBConnection();
    }
  
    // Method 1
    public void createStudentDBConnection()
        throws ClassNotFoundException, SQLException
    {
  
        // Loading driver
        // using forName() method
        Class.forName(driver);
  
        // Getting a connection
        // using DriverManager
        con = DriverManager.getConnection(url, userName,
                                          password);
  
        // Executing query
        stmt = con.createStatement();
    }
  
    // Method 2
    public void selectAllRows()
        throws ClassNotFoundException, SQLException
    {
  
        // Display command
        System.out.println("Retrieving all student data..");
  
        // Storing in a ResultSet
        ResultSet rs = stmt.executeQuery(
            "SELECT * FROM studentdb.hostelstudentinfo");
  
        // Iterating
        while (rs.next()) {
            int studentId = rs.getInt(1);
            String studentName = rs.getString(2);
            double hostelFees = rs.getDouble(3);
            String foodType = rs.getString(4);
  
            // Printing corresponding student attributes
            System.out.println(studentId + " " + studentName
                               + " " + hostelFees + " "
                               + foodType);
        }
    }
  
    // Method 3
    public void deleteStudentRecord(int studentId)
        throws ClassNotFoundException, SQLException
    {
        System.out.println("Delete student data..");
  
        stmt.executeUpdate(
            "delete from studentdb.hostelstudentinfo where Student_id = "
            + studentId);
        System.out.println("Record Deleted with the ID "
                           + studentId);
    }
  
    // Method 4
    public void closeConnection() throws SQLException
    {
        con.close();
    }
  
    // Method 5
    @PreDestroy public void destroy() throws SQLException
    {
        closeConnection();
    }
}


Before running the application make sure you have added the following line inside your beans.xml file to use the annotation

<context:annotation-config/>

File: beans.xml 

XML




<?xml version="1.0" encoding="UTF-8"?>
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  
    <context:annotation-config/>
  
    <bean id="studentDAO" class="StudentDAO">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/studentdb"/>
        <property name="userName" value="root"/>
        <property name="password" value="143@Arpilu"/>
    </bean>
  
</beans>


File: Main.java

Java




// Java Program to Illustrate Application Class
  
// Importing required classes
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
  
// Application Class
public class Main {
  
    // Main driver method
    public static void main(String[] args)
        throws SQLException, ClassNotFoundException
    {
  
        // Using ApplicationContext tom implement Spring IoC
        ApplicationContext context
            = new ClassPathXmlApplicationContext(
                "beans.xml");
  
        // Getting the bean studentDAO
        StudentDAO studentDAO = context.getBean(
            "studentDAO", StudentDAO.class);
  
        // Calling the method
        // inside main() method
        studentDAO.deleteStudentRecord(2);
        studentDAO.selectAllRows();
    }
}


Output:

Delete student data..
Record Deleted with the ID 2
Retrieving all student data..
1 Asish 300.5 Veg
3 Anshul 123.67 Veg


Last Updated : 11 Mar, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads