Odpowiedzi:
ponieważ gdy wywoływany jest konstruktor, komponent bean nie jest jeszcze inicjowany - tzn. nie są wstrzykiwane żadne zależności. W @PostConstruct
metodzie fasola jest w pełni inicjowana i można korzystać z zależności.
ponieważ jest to umowa gwarantująca, że ta metoda zostanie wywołana tylko raz w cyklu życia komponentu bean. Może się zdarzyć (choć mało prawdopodobne), że fasola jest wielokrotnie inicjowana przez kontener w swoim wewnętrznym działaniu, ale gwarantuje, że @PostConstruct
zostanie wywołany tylko raz.
Głównym problemem jest to, że:
w konstruktorze wstrzyknięcie zależności jeszcze nie nastąpiło *
* oczywiście z wyłączeniem wtrysku konstruktora
Przykład ze świata rzeczywistego:
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
i @PreDestroy
zostały całkowicie usunięte w Javie 11 .
Aby nadal ich używać, musisz dodać plik JAR javax.annotation-api do swoich zależności.
<!-- 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>
// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
in a constructor, the injection of the dependencies has not yet occurred.
prawda z zastrzykiem setera lub pola, ale nie prawda z zastrzykiem konstruktora.
Jeśli twoja klasa wykonuje całą inicjalizację w konstruktorze, @PostConstruct
to rzeczywiście jest zbędna.
Jeśli jednak w twojej klasie wstrzyknięto zależności za pomocą metod ustawiających, wówczas konstruktor klasy nie może w pełni zainicjować obiektu, a czasem po zainicjowaniu wszystkich metod ustawiających należy wykonać pewną inicjalizację, stąd przypadek użycia @PostConstruct
.
Rozważ następujący scenariusz:
public class Car {
@Inject
private Engine engine;
public Car() {
engine.initialize();
}
...
}
Ponieważ Car musi zostać utworzony przed iniekcją w terenie, silnik punktu iniekcji jest nadal zerowy podczas wykonywania konstruktora, co powoduje wyjątek NullPointerException.
Ten problem można rozwiązać za pomocą wstrzykiwania zależności JSR-330 dla wstrzykiwania konstruktora Java lub zwykłych adnotacji JSR 250 dla adnotacji metody @PostConstruct w języku Java.
@PostConstruct
JSR-250 definiuje wspólny zestaw adnotacji, który został zawarty w Java SE 6.
Adnotacja PostConstruct jest używana w metodzie, którą należy wykonać po wykonaniu wstrzyknięcia zależności w celu wykonania dowolnej inicjalizacji. Ta metoda MUSI zostać wywołana przed oddaniem klasy do użytku. Ta adnotacja MUSI być obsługiwana we wszystkich klasach obsługujących wstrzykiwanie zależności.
JSR-250 Rozdz. 2.5 javax.annotation.PostConstruct
Adnotacja @PostConstruct pozwala na zdefiniowanie metod, które będą wykonywane po utworzeniu instancji i wykonaniu wszystkich wstrzyknięć.
public class Car {
@Inject
private Engine engine;
@PostConstruct
public void postConstruct() {
engine.initialize();
}
...
}
Zamiast inicjowania w konstruktorze kod jest przenoszony do metody opatrzonej adnotacją @PostConstruct.
Przetwarzanie metod postkonstrukcyjnych polega na znalezieniu wszystkich metod opatrzonych adnotacją @PostConstruct i wywołaniu ich z 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 postkonstrukcyjnych należy wykonać po zakończeniu tworzenia instancji i wstrzyknięcia.
Inicjalizacja oparta na konstruktorach nie będzie działać zgodnie z przeznaczeniem, ilekroć w grę wchodzi jakieś proxy lub zdalne zarządzanie.
CT będzie wywoływany za każdym razem, gdy EJB zostanie zdezrializowany i za każdym razem, gdy zostanie dla niego stworzony nowy serwer proxy ...
final
. Biorąc pod uwagę ten wzorzec, dlaczego jest@PostConstruct
dodawany do J2EE - z pewnością widzieli inny przypadek użycia?