Dlaczego warto używać @PostConstruct?

W managed bean, {[0] } jest wywoływany po zwykłym konstruktorze obiektów Java.

Dlaczego miałbym używać @PostConstruct do inicjalizacji przez bean,zamiast zwykłego konstruktora?

Author: Jan, 2010-08-04

5 answers

  • Ponieważ po wywołaniu konstruktora, bean nie jest jeszcze zainicjalizowany - tzn. nie są wstrzykiwane żadne zależności. W metodzie @PostConstruct bean jest w pełni zainicjalizowany i można używać zależności.

  • Ponieważ jest to umowa, która gwarantuje, że ta metoda będzie wywoływana tylko raz w cyklu życia bean. Może się zdarzyć (choć mało prawdopodobne), że fasola jest wielokrotnie inicjowana przez kontener w jego wewnętrznej pracy, ale gwarantuje to, że @PostConstruct będzie wywołana tylko raz.

 448
Author: Bozho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-05 13:20:40

główny problem polega na tym, że:

W konstruktorze nie doszło jeszcze do iniekcji zależności*

*oczywiście z wyłączeniem iniekcji konstruktora


Przykład w świecie rzeczywistym:

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

Ważne : @PostConstruct oraz @PreDestroy zostały całkowicie usunięte w Javie 11.

Aby nadal z nich korzystać, musisz dodać javax.adnotacja-api JAR do twojego zależności.

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'
 111
Author: Andrea Ligios,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-30 10:04:29

Jeśli twoja klasa wykonuje całą inicjalizację w konstruktorze, to {[0] } jest rzeczywiście zbędna.

Jednakże, jeśli twoja klasa ma swoje zależności wstrzykiwane za pomocą metod settera, to konstruktor klasy nie może w pełni zainicjować obiektu, a czasami trzeba wykonać inicjalizację po wywołaniu wszystkich metod settera, stąd przypadek użycia @PostConstruct.

 67
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-04 14:46:59

Rozważ następujący scenariusz:

public class Car {
  @Inject
  private Engine engine;  

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

Ponieważ samochód musi być uruchamiany przed wtryskiem w polu, silnik punktu wtrysku jest nadal zerowy podczas wykonywania konstruktora, co skutkuje wyrażeniem NullPointerException.

Ten problem można rozwiązać poprzez JSR-330 Dependency Injection for Java constructor injection lub wspólne adnotacje JSR 250 dla adnotacji metody Java @PostConstruct.

@PostConstruct

JSR-250 definiuje common set of adnotations which has been included in Java SE 6.

Adnotacja PostConstruct jest używana w metodzie, która musi być wykonywany po wykonaniu iniekcji zależności w celu wykonania dowolnego inicjalizacja. Ta metoda musi być wywołana przed wprowadzeniem klasy do użytku. Ta adnotacja musi być obsługiwana na wszystkich klasach, które wsparcie dependency injection.

JSR-250 2.5 javax.adnotacja.PostConstruct

Adnotacja @PostConstruct pozwala na zdefiniowanie metod, które mają być wykonywane po utworzeniu instancji i wykonaniu wszystkich iniekcji.

public class Car {
  @Inject
  private Engine engine;  

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

Zamiast inicjalizacji w konstruktorze, kod jest przenoszony do metody z adnotacją @PostConstruct.

Przetwarzanie metod post-construct polega na znalezieniu wszystkich metod opatrzonych adnotacją @PostConstruct i wywołaniu ich po kolei.

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);
        }
      });
}

Przetwarzanie metod post-construct musi być wykonywane po zakończeniu tworzenia instancji i iniekcji.

 11
Author: Humoyun Ahmad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-18 06:43:57

Również inicjalizacja oparta na konstruktorze nie będzie działać zgodnie z założeniami, gdy w grę wchodzi jakieś proxy lub remoting.

Ct zostanie wywołany za każdym razem, gdy EJB zostanie deserializowany i gdy zostanie utworzony nowy proxy dla niego...

 1
Author: struberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-16 15:34:30