411

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?

Jan
  • 9,397
  • 13
  • 47
  • 52
  • 7
    I got the impression that constructor injection was generally preferred to allow dependencies to be `final`. Given that pattern, why is `@PostConstruct` being added to J2EE - they must have seen another use case surely? – mjaggard Jan 10 '18 at 08:58
  • @mjaggard my understanding is that `@PostConstruct` is not used to inject your dependencies appropriately, to make sure they are `final`, etc; it is used as an annotation for a utility that should be called *exactly once* even if the object is constructed multiple times by the IoC container. Not that I know how this would happen in the container, but it apparently can happen (see accepted answer). – Jason Jun 29 '21 at 17:06

4 Answers4

557
  • 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.

  • because 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.

Jasper
  • 2,166
  • 4
  • 30
  • 50
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 30
    in case the constructor itself autowires all dependencies - then the bean can also be fully initialized in the constructor (after setting manually all autowired fields). – yair Mar 20 '13 at 09:49
  • 8
    what's the case in which a bean's constructor may be called more than once? – yair Mar 20 '13 at 09:51
  • 2
    Probably something like "passivation". If the container decides to store the bean on the disk store and then restore it from there. – Bozho Mar 20 '13 at 09:57
  • 14
    It's not that unlikely to see the constructor called multiple times. When the container instantiates a proxy, you will see that constructor is called at least once for the proxy and once for the real bean. – marcus Mar 17 '14 at 16:16
  • Note that @PostConstruct methods are *not* called when the page is loaded immediately after a server restart. (This might be a JBoss bug.) – Dave Jarvis Nov 14 '16 at 18:36
  • @PostConstruct gets called twice, have you faced such issue? – iamrajshah Jan 16 '19 at 05:44
  • @yair The constructor in the class is a Java language feature. It is called by the JVM as part of the object creation. Its not possible for the constructor to be called more than once. – sudhir shakya Nov 06 '19 at 05:56
  • @sudhirshakya 6 years distant from my comment, it seems that this was exactly my point. Hard for my to judge, again, because of the time that has passed, but also seems that Bozho has answered it well. – yair Nov 07 '19 at 07:43
  • I found the @PostConstruct useful to load the data from repository (had repository injected in service class) and assign it to the same class member field. It allowed me to pull data from DB once and then reuse it in each and every method in that service class, whenever needed, without additional calls to the DB – Przemek Jan 30 '20 at 08:28
  • @Przemek You can do the same without using `@PostConstruct` as well. – narendra-choudhary Feb 04 '20 at 18:07
  • @narendra-choudhary How? As far as I know, in the moment of using constructor of my service, no dependencies (repository) are yet wired into constructor. – Przemek Feb 05 '20 at 15:08
  • Just be careful, if you have circular dependencies they will have been injected but possibly not had their `@PostConstruct` methods called on them yet so best to not use them... – rogerdpack Oct 29 '20 at 19:26
  • Just be careful, if you have circular dependencies, it is possible that your AutoWired's AutoWired dependencies will still be null at PostConstruct time: https://stackoverflow.com/a/64649202/32453 – rogerdpack Nov 02 '20 at 16:16
  • I think Spring guarantees that singletons are created only once. If anyone claims this isn't the case then I would ask for more concrete evidence. I think the below answer is correct : https://stackoverflow.com/a/3406690/157591 @PostConstruct was designed to work with setter injection. If you use constructor injection then it isn't needed – Peter Szanto Jun 27 '22 at 11:33
144

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'
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • 28
    `in a constructor, the injection of the dependencies has not yet occurred. ` true with setter or field injection, but not true with constructor injection. – Adam Siemion Nov 09 '15 at 11:00
  • With @PostConstruct being removed in Java 11, how can we now handle this real world example with Java 11? – tet Oct 30 '18 at 09:40
  • @tet As mentioned in answer, you need to use javax.annotation-api library. These annotations were removed in Java 11, but were already marked deprecated since Java 9. – narendra-choudhary Feb 04 '20 at 18:01
  • I can still see `@PostConstruct` in `java 11` – Rookie007 Nov 17 '21 at 14:45
  • @Rookie007 if you check in your classpath you will notice you're using javax.annotation-api jar – soung Jul 17 '22 at 15:21
77

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.

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • @staffman: plus one from my side. If i wish to initialise an inputtext field with a value fetched from database, I am able to do it with the help of PostConstruct, but fails when try to do the same inside the constructor. I have this requirement to initialise without the use of PostContruct. If you have time, can you please answer this one also: http://stackoverflow.com/questions/27540573/how-to-initialize-inputtextfield-with-a-value-from-database-on-runtime-without-t – Farhan stands with Palestine Dec 22 '14 at 13:18
1

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...

struberg
  • 730
  • 5
  • 12