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.