[java] Why use @PostConstruct?

In a managed bean, @PostConstruct is called after the regular Java object constructor.

Why would I use @PostConstruct to initialize by bean, instead of the regular constructor itself?

This question is related to java dependency-injection jakarta-ee cdi jsr299

The answer is


Also constructor based initialisation will not work as intended whenever some kind of proxying or remoting is involved.

The ct will get called whenever an EJB gets deserialized, and whenever a new proxy gets created for it...


The main problem is that:

in a constructor, the injection of the dependencies has not yet occurred*

*obviously excluding Constructor Injection


Real-world example:

public class Foo {

    @Inject
    Logger LOG;

    @PostConstruct
    public void fooInit(){
        LOG.info("This will be printed; LOG has already been injected");
    }

    public Foo() {
        LOG.info("This will NOT be printed, LOG is still null");
        // NullPointerException will be thrown here
    }
}

IMPORTANT: @PostConstruct and @PreDestroy have been completely removed in Java 11.

To keep using them, you'll need to add the javax.annotation-api JAR to your dependencies.

Maven

<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

Gradle

// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'

Consider the following scenario:

public class Car {
  @Inject
  private Engine engine;  

  public Car() {
    engine.initialize();  
  }
  ...
}

Since Car has to be instantiated prior to field injection, the injection point engine is still null during the execution of the constructor, resulting in a NullPointerException.

This problem can be solved either by JSR-330 Dependency Injection for Java constructor injection or JSR 250 Common Annotations for the Java @PostConstruct method annotation.

@PostConstruct

JSR-250 defines a common set of annotations which has been included in Java SE 6.

The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. This method MUST be invoked before the class is put into service. This annotation MUST be supported on all classes that support dependency injection.

JSR-250 Chap. 2.5 javax.annotation.PostConstruct

The @PostConstruct annotation allows for the definition of methods to be executed after the instance has been instantiated and all injects have been performed.

public class Car {
  @Inject
  private Engine engine;  

  @PostConstruct
  public void postConstruct() {
    engine.initialize();  
  }
  ...
} 

Instead of performing the initialization in the constructor, the code is moved to a method annotated with @PostConstruct.

The processing of post-construct methods is a simple matter of finding all methods annotated with @PostConstruct and invoking them in turn.

private  void processPostConstruct(Class type, T targetInstance) {
  Method[] declaredMethods = type.getDeclaredMethods();

  Arrays.stream(declaredMethods)
      .filter(method -> method.getAnnotation(PostConstruct.class) != null) 
      .forEach(postConstructMethod -> {
         try {
           postConstructMethod.setAccessible(true);
           postConstructMethod.invoke(targetInstance, new Object[]{});
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {      
          throw new RuntimeException(ex);
        }
      });
}

The processing of post-construct methods has to be performed after instantiation and injection have been completed.


If your class performs all of its initialization in the constructor, then @PostConstruct is indeed redundant.

However, if your class has its dependencies injected using setter methods, then the class's constructor cannot fully initialize the object, and sometimes some initialization needs to be performed after all the setter methods have been called, hence the use case of @PostConstruct.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to dependency-injection

Are all Spring Framework Java Configuration injection examples buggy? Passing data into "router-outlet" child components ASP.NET Core Dependency Injection error: Unable to resolve service for type while attempting to activate Error when trying to inject a service into an angular component "EXCEPTION: Can't resolve all parameters for component", why? org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoRestController' How to inject window into a service? How to get bean using application context in spring boot Resolving instances with ASP.NET Core DI from within ConfigureServices How to inject a Map using the @Value Spring Annotation? WELD-001408: Unsatisfied dependencies for type Customer with qualifiers @Default

Examples related to jakarta-ee

Java 11 package javax.xml.bind does not exist javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure The type java.io.ObjectInputStream cannot be resolved. It is indirectly referenced from required .class files Deploying Maven project throws java.util.zip.ZipException: invalid LOC header (bad signature) web.xml is missing and <failOnMissingWebXml> is set to true WELD-001408: Unsatisfied dependencies for type Customer with qualifiers @Default Name [jdbc/mydb] is not bound in this Context An internal error occurred during: "Updating Maven Project". java.lang.NullPointerException How to consume a SOAP web service in Java java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer

Examples related to cdi

Identifying and solving javax.el.PropertyNotFoundException: Target Unreachable WELD-001408: Unsatisfied dependencies for type Customer with qualifiers @Default Should I use @EJB or @Inject Why use @PostConstruct?

Examples related to jsr299

Why use @PostConstruct?