Spring @PostConstruct Annotation with Example





Hey guys, in this post we will discuss spring @PostConstruct annotation with example.

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.



Bushan Sirgur

Hey guys, I am Bushan Sirgur from Banglore, India. Currently, I am working as an Associate project in an IT company.

Leave a Reply