Open In App

Spring – @PostConstruct and @PreDestroy Annotation with Example

Last Updated : 10 Mar, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Spring is one of the most popular Java EE frameworks. It is an open-source lightweight framework that allows Java EE 7 developers to build simple, reliable, and scalable enterprise applications. This framework mainly focuses on providing various ways to help you manage your business objects. It made the development of Web applications much easier than compared to classic Java frameworks and application programming interfaces (APIs), such as Java database connectivity (JDBC), JavaServer Pages(JSP), and Java Servlet. This framework uses various new techniques such as Aspect-Oriented Programming (AOP), Plain Old Java Object (POJO), and dependency injection (DI), to develop enterprise applications. Now talking about Spring Annotation

Spring Annotations are a form of metadata that provides data about a program. Annotations are used to provide supplemental information about a program. It does not have a direct effect on the operation of the code they annotate. It does not change the action of the compiled program. 

So what happens is, whenever we configure Spring Beans using dependency injection, sometimes we want to make sure everything is initialized correctly before the bean starts serving the client requests. Likewise, when the context is destroyed, we may have to close some resources utilized by spring beans. 

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

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.

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:

A. If you are using Maven

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

B. If you add the jar manually

Visit the link and inside the files column, you will 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. You may refer to this article to Add External JAR File to an IntelliJ IDEA Project or refer to this one to 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.

Implementation: We are going to explain @PostConstruct and @PreDestroy Annotation by simply creating a Spring JDBC project. So let’s create a Spring JDBC project first. 

Prerequisite: JDBC Tutorial

Step 1: Create a simple Java project in your preferred IDE (IntelliJ IDEA or Eclipse). You may refer to these articles:

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 these articles:

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.

  • Driver
  • URL
  • User
  • 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
    public void selectAllRows()
        throws ClassNotFoundException, SQLException
    {
        System.out.println("Retrieving all 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();
 
        ResultSet rs = stmt.executeQuery(
            "SELECT * FROM studentdb.hostelstudentinfo");
 
        // Iterating over till condition holds true
        while (rs.next()) {
            int studentId = rs.getInt(1);
            String studentName = rs.getString(2);
            double hostelFees = rs.getDouble(3);
            String foodType = rs.getString(4);
 
            // Print statement
            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

 

You may download the jar file from the following links:

 

 

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. You may refer to this article Spring – Injecting Literal Values By Setter Injection. Below is the code for the beans.xml file.

 

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. Below is the code for the Main.java file.

 

Java




// Java Program to Illustrate Application File
 
// 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
    {
 
        // Implementing Spring IoC
        // using ApplicationContext
        ApplicationContext context
            = new ClassPathXmlApplicationContext(
                "beans.xml");
 
        // Getting 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

Note: 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 shown in below example as follows: 

 

Example

 

Java




// Java Program Illustrating Method to Delete Student Record
 
public void deleteStudentRecord(int studentId)
    throws ClassNotFoundException, SQLException
{
    // Display message
    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);
    System.out.println("Record Deleted with the ID "
                       + studentId);
 
    // Closing the connections
    // 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()

 

Example

 

Java




// Java Program Illustrating Method to Create StudentDB
// Connection
 
// Method
public void createStudentDBConnection()
    throws ClassNotFoundException, SQLException
{
 
    // Loading driver
    Class.forName(driver);
 
    // Getting a connection
    con = DriverManager.getConnection(url, userName,
                                      password);
 
    // Executing a 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.

 

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;
 
    // 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;
    }
 
    // Creating connection
    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();
    }
 
    // Method 1
    public void selectAllRows()
        throws ClassNotFoundException, SQLException
    {
        System.out.println("Retrieving all student data..");
 
        // Create connection
        createStudentDBConnection();
 
        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
        closeConnection()
    }
 
    // Method 2
    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 3
    // 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. 

 

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

 

Java




@PostConstruct
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
        // load driver
        Class.forName(driver);
 
        // get a connection
        con = DriverManager.getConnection(url, userName, password);
 
        // execute 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

 

Java




@PostConstruct
public void init() throws SQLException, ClassNotFoundException {
        createStudentDBConnection();
    }
 
public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
        // load driver
        Class.forName(driver);
 
        // get a connection
        con = DriverManager.getConnection(url, userName, password);
 
        // execute 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 something like that

 

Java




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


 

 

Note that we can also use the @PreDestroy annotation before the closeConnection() method. Now the complete code for the StudentDAO.java class is

 

Java




import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.sql.*;
 
public class StudentDAO {
 
    private String driver;
    private String url;
    private String userName;
    private String password;
 
    // Connection Object
    Connection con;
 
    // Statement Object
    Statement stmt;
 
    public void setDriver(String driver) {
        this.driver = driver;
    }
 
    public void setUrl(String url) {
        this.url = url;
    }
 
    public void setUserName(String userName) {
        this.userName = userName;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    @PostConstruct
    public void init() throws SQLException, ClassNotFoundException {
        createStudentDBConnection();
    }
 
    public void createStudentDBConnection() throws ClassNotFoundException, SQLException {
        // load driver
        Class.forName(driver);
 
        // get a connection
        con = DriverManager.getConnection(url, userName, password);
 
        // execute query
        stmt = con.createStatement();
    }
 
    public void selectAllRows() throws ClassNotFoundException, SQLException {
 
        System.out.println("Retrieving all student data..");
 
        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);
        }
    }
 
    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);
    }
 
    public void closeConnection() throws SQLException {
        con.close();
    }
 
    @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/>

 

The complete code for the beans.xml file is given below

 

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>


 

 

The complete code for the Main.java file is given below

 

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.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

 



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads