Why use @PostConstruct?
Asked Answered
M

5

424

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?

Mccarley answered 4/8, 2010 at 14:32 Comment(2)
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?Altman
@Altman 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).Glary
C
570
  • 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.

Chouinard answered 4/8, 2010 at 14:40 Comment(15)
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).Sacci
what's the case in which a bean's constructor may be called more than once?Sacci
Probably something like "passivation". If the container decides to store the bean on the disk store and then restore it from there.Chouinard
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.Anissa
Note that @PostConstruct methods are not called when the page is loaded immediately after a server restart. (This might be a JBoss bug.)Unjust
@PostConstruct gets called twice, have you faced such issue?Aristocratic
@Sacci 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.Inviolate
@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.Sacci
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 DBGlume
@Glume You can do the same without using @PostConstruct as well.Multiangular
@Multiangular How? As far as I know, in the moment of using constructor of my service, no dependencies (repository) are yet wired into constructor.Glume
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...Orpine
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://mcmap.net/q/82110/-spring-circular-dependencies-postconstruct-and-order-imposed-by-dependsonOrpine
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://mcmap.net/q/80883/-why-use-postconstruct @PostConstruct was designed to work with setter injection. If you use constructor injection then it isn't neededTideway
Neither of these reasons are valid: (1) Spring itself advises against using Field injection, so don't do that (2) You can't call the constructor multiple times in a single instances lifecycle, as other folks pointed out.Samsara
H
146

You always should prefer constructor injection, but having that said, if for any reason you have to use field injection, in that case the main problem is that:

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


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](https://jaxenter.com/jdk-11-java-ee-modules-140674.html).

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'
Henbit answered 27/11, 2014 at 14:33 Comment(5)
in a constructor, the injection of the dependencies has not yet occurred. true with setter or field injection, but not true with constructor injection.Alvertaalves
With @PostConstruct being removed in Java 11, how can we now handle this real world example with Java 11?Gasconade
@Gasconade 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.Multiangular
I can still see @PostConstruct in java 11Shammer
@Shammer if you check in your classpath you will notice you're using javax.annotation-api jarPlayhouse
H
79

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.

Hann answered 4/8, 2010 at 14:46 Comment(1)
@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: #27541073Swanherd
A
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...

Anglo answered 16/10, 2011 at 15:34 Comment(0)
S
0

There is only really one reason - because you want to take an action that requires the object to be fully constructed, like passing the "this" reference to an executor.

All the other reasons only occur if you fail to write code according to best practices (e.g. using field injections instead of constructor injection, etc).

But, since Java is free to re-order instructions in constructors, you cannot depend on any one field being fully constructed before handing off a reference to the object to an executor (i.e, the this reference should not escape until the constructor is finished)

Samsara answered 17/1 at 22:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.