Why use @PostConstruct?

后端 未结 5 698
孤街浪徒
孤街浪徒 2020-11-22 11:49

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

Why would I use @PostConstruct to initialize by bean

相关标签:
5条回答
  • 2020-11-22 12:20
    • 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.

    0 讨论(0)
  • 2020-11-22 12:27

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

    0 讨论(0)
  • 2020-11-22 12:33

    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.

    0 讨论(0)
  • 2020-11-22 12:35

    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'
    
    0 讨论(0)
  • 2020-11-22 12:37

    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.

    0 讨论(0)
提交回复
热议问题