In this article, we will discuss how to use the @PostConstruct and @PreDestroy
annotations in a Spring Boot
application. These annotations are part of the Java EE specification and are used to define lifecycle
callback methods for a bean.
The @PostConstruct annotation is used on a method that needs to be executed after dependency
injection is
done to perform any initialization. Similarly, the @PreDestroy annotation is used on methods
that need to be
executed before the bean is destroyed. These annotations are particularly useful for resource management and
cleanup tasks.
This annotation is used on a method that needs to be run after the bean has been initialized and all dependencies have been injected. It is typically used for performing any setup or initialization tasks that need to be done after the bean's properties have been set.
This annotation is used on a method that needs to be run before the bean is destroyed. It is typically used for cleanup tasks such as releasing resources or closing connections.
Let's create a simple Maven project to demonstrate the usage of @PostConstruct and
@PreDestroy annotations in
a Spring application.
Create a simple Maven project using your favourite IDE. Below is the project structure for your reference:
src
├── main
│ ├── java
│ │ └── net
│ │ └── javaguides
│ │ └── spring
│ │ ├── AppConfig.java
│ │ ├── Application.java
│ │ ├── MessageService.java
│ │ ├── MessageServiceImpl.java
│ │ └── DatabaseService.java
│ └── resources
│ └── application.properties
Make sure to use Java 17 or later for Spring Framework 6:
<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
<groupId>net.javaguides
<artifactId>spring-postconstruct-predestroy
<version>1.0-SNAPSHOT
<properties>
<maven.compiler.source>17
<maven.compiler.target>17
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot
<artifactId>spring-boot-starter
<version>3.0.0
</dependency>
<dependency>
<groupId>org.springframework.boot
<artifactId>spring-boot-starter-data-jpa
<version>3.0.0
</dependency>
<dependency>
<groupId>com.h2database
<artifactId>h2
<scope>runtime
</dependency>
</dependencies>
</project>
In a real-world application, you might need to initialize a database at startup and clean up resources when
the application shuts down. The @PostConstruct and @PreDestroy annotations are
perfect for such tasks.
MessageService.java
package net.javaguides.spring;
public interface MessageService {
String getMessage();
}
MessageServiceImpl.java
package net.javaguides.spring;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Component;
@Component
public class MessageServiceImpl implements MessageService {
private String message;
@PostConstruct
public void init() {
message = "Hello, Spring!";
System.out.println("PostConstruct: MessageService initialized with message: " + message);
}
@Override
public String getMessage() {
return message;
}
@PreDestroy
public void cleanup() {
System.out.println("PreDestroy: Cleaning up resources...");
}
}
DatabaseService.java
package net.javaguides.spring;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.Statement;
@Component
public class DatabaseService {
private final DataSource dataSource;
public DatabaseService(DataSource dataSource) {
this.dataSource = dataSource;
}
@PostConstruct
public void initDatabase() {
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.execute("CREATE TABLE IF NOT EXISTS Users (id INT AUTO_INCREMENT, name VARCHAR(255), PRIMARY KEY (id))");
statement.execute("INSERT INTO Users (name) VALUES ('John Doe')");
System.out.println("PostConstruct: Database initialized");
} catch (Exception e) {
e.printStackTrace();
}
}
@PreDestroy
public void cleanupDatabase() {
try (Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement()) {
statement.execute("DROP TABLE IF EXISTS Users");
System.out.println("PreDestroy: Database cleaned up");
} catch (Exception e) {
e.printStackTrace();
}
}
}
AppConfig.java
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 {
}
Application.java
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);
MessageService messageService = context.getBean(MessageService.class);
System.out.println("Message from MessageService: " + messageService.getMessage());
context.close();
}
}
In this class:
AnnotationConfigApplicationContext is used to create and manage the Spring application
context.context.getBean(MessageService.class) retrieves a bean of type MessageService from the
Spring context.close method on context triggers the @PreDestroy method.When you run the Application class, you should see the following output:
PostConstruct: Database initialized
PostConstruct: MessageService initialized with message: Hello, Spring!
Message from MessageService: Hello, Spring!
PreDestroy: Cleaning up resources...
PreDestroy: Database cleaned up
Explanation:
initDatabase method is called after the DatabaseService bean is
initialized, setting up the database and inserting initial data.init method is called after the MessageServiceImpl bean is initialized,
setting the message and
printing the initialization message.getMessage method prints the message to the console.cleanup method is called before the MessageServiceImpl bean is destroyed,
cleaning up any resources.cleanupDatabase method is called before the DatabaseService bean is
destroyed, dropping the database table.In this article, we demonstrated how to use the @PostConstruct and @PreDestroy
annotations in a Spring Boot
application. By using these annotations, we can perform initialization and cleanup tasks for our beans. The
example showed how to initialize a database at startup and clean up resources when the application shuts
down, which is a common real-world use case.