Hey guys, in this post we will discuss spring @PostConstruct
annotation with example.
Table of Contents
Overview
@PostConstruct
can be applied to a method, the given bean is executed after all injections have been done. @PostConstruct
is executed after injections are committed to the given bean. This is the reason it exists.
This is the contract that guarantees that this method will be invoked only once in the bean lifecycle. It may happen (though unlikely) that a bean is instantiated multiple times by the container in its internal working, but it guarantees that @PostConstruct
will be invoked only once.
@RestController
public class CustomerController {
@Autowired
CustomerService cService;
@PostConstruct
public void getCustomer () {
//get the customer
}
}
Watch the video
Example on @PostConstruct
The best way to understand @PostConstruct
is by looking at the example
Create spring boot project
There are many different ways to create a spring boot application, you can follow the below articles to create one –
>> Create spring boot application using Spring initializer
>> Create spring boot application in Spring tool suite [STS]
>> Create spring boot application in IntelliJ IDEA
Add maven dependencies
Open pom.xml
and add the following dependencies –
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>in.bushansirgur</groupId>
<artifactId>postconstruct</artifactId>
<version>v1</version>
<name>postconstruct</name>
<description>Spring boot post construct</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
spring-boot-starter-web
dependency for building web applications using Spring MVC. It uses the tomcat as the default embedded container.
spring-boot-devtools
dependency for automatic reloads or live reload of applications.
Create an entity class
Create Customer.java
inside the in.bushansirgur.springboot.entity
package and add the following content
package in.bushansirgur.springboot.entity;
public class Customer {
private String name;
private String location;
public Customer(String name, String location) {
super();
this.name = name;
this.location = location;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
@Override
public String toString() {
return "Customer [name=" + name + ", location=" + location + "]";
}
}
This is just a plain old java class that has private fields, setters, getters, and constructors.
Create a service
Create CustomerService.java
inside the in.bushansirgur.springboot.service
package and add the following content
package in.bushansirgur.springboot.service;
import org.springframework.stereotype.Service;
import in.bushansirgur.springboot.entity.Customer;
@Service
public class CustomerService {
public CustomerService() {
System.out.println("constructor:customer service");
}
public Customer get () {
return new Customer("customer", "india");
}
}
Create a Rest controller
Create CustomerController.java
inside the in.bushansirgur.springboot.controller
package and add the following content
package in.bushansirgur.springboot.controller;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import in.bushansirgur.springboot.entity.Customer;
import in.bushansirgur.springboot.service.CustomerService;
@RestController
public class CustomerController {
@Autowired
CustomerService cService;
public CustomerController() {
System.out.println("constructor: customer controller");
}
@PostConstruct
public void getCustomer () {
System.out.println("getCustomer() is calling");
System.out.println(cService.get());
}
}
We are annotating @PostConstruct
annotation to getCustomer()
method and inside this method, we are calling the get()
method of CustomerService
.
Run the app
Run the application using the below maven command –
mvn spring-boot:run
Output:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.3)
2021-03-07 19:32:40.571 INFO 51987 --- [ restartedMain] i.b.springboot.PostconstructApplication : Starting PostconstructApplication using Java 1.8.0_151 on MacBook-Air.local with PID 51987 (/Users/bushansirgur/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-examples/postconstruct/target/classes started by bushansirgur in /Users/bushansirgur/Documents/workspace-spring-tool-suite-4-4.9.0.RELEASE/spring-boot-examples/postconstruct)
2021-03-07 19:32:40.571 INFO 51987 --- [ restartedMain] i.b.springboot.PostconstructApplication : No active profile set, falling back to default profiles: default
2021-03-07 19:32:40.724 INFO 51987 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-03-07 19:32:40.724 INFO 51987 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-03-07 19:32:40.725 INFO 51987 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.43]
2021-03-07 19:32:40.730 INFO 51987 --- [ restartedMain] o.a.c.c.C.[Tomcat-5].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-03-07 19:32:40.730 INFO 51987 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 155 ms
constructor: customer controller
constructor:customer service
getCustomer() is calling
Customer [name=customer, location=india]
2021-03-07 19:32:40.772 INFO 51987 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-07 19:32:40.802 INFO 51987 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2021-03-07 19:32:40.809 INFO 51987 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-03-07 19:32:40.812 INFO 51987 --- [ restartedMain] i.b.springboot.PostconstructApplication : Started PostconstructApplication in 0.475 seconds (JVM running for 5012.569)
2021-03-07 19:32:40.814 INFO 51987 --- [ restartedMain] .ConditionEvaluationDeltaLoggingListener : Condition evaluation unchanged
Now try to call get()
method of CustomerService
inside the constructor, you will get NullPointerException
Caused by: java.lang.NullPointerException: null
at in.bushansirgur.springboot.controller.CustomerController.(CustomerController.java:23) ~[classes/:na]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_151]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_151]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_151]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_151]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:212) ~[spring-beans-5.3.4.jar:5.3.4]
... 25 common frames omitted
Because, when the constructor is called, the bean is not yet initialized – i.e. no dependencies are injected. In the @PostConstruct
method, the bean is fully initialized and you can use the dependencies.