2010-08-04 8 views
196

W zarządzanym komponencie bean, @PostConstruct jest wywoływana za zwykłym konstruktorem obiektów Java.Dlaczego warto korzystać z @PostConstruct?

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

+0

Odniosłem wrażenie, że wstrzyknięcie konstruktora było na ogół preferowane, aby zezwalać zależnościom na "końcowe". Biorąc pod uwagę ten wzór, dlaczego '@ PostConstruct' jest dodawany do J2EE - na pewno widzieli inny przypadek użycia? – mjaggard

Odpowiedz

288
  • ponieważ gdy konstruktor jest wywoływana, fasola nie jest zainicjowana - czyli nie występują żadne zależności wstrzykuje. W metodzie @PostConstruct komponent bean jest w pełni zainicjowany i można użyć zależności.

  • ponieważ jest to umowa, która gwarantuje, że ta metoda zostanie wywołana tylko jeden raz w cyklu życia fasoli. Może się zdarzyć (choć jest mało prawdopodobne), że komponent bean w instancji wewnętrznej jest tworzony wiele razy, ale gwarantuje, że zostanie wywołany tylko jeden raz.

+7

w przypadku, gdy sam konstruktor autowyresuje wszystkie zależności - wówczas komponent bean może zostać w pełni zainicjowany w konstruktorze (po ręcznym ustawieniu wszystkich pól z autowyredami). – yair

+3

w jakim przypadku konstruktor komponentu bean może być wywoływany więcej niż jeden raz? – yair

+0

Prawdopodobnie coś w rodzaju "pasywacji". Jeśli kontener zdecyduje się zapisać komponent bean w magazynie dyskowym, a następnie go przywrócić. – Bozho

45

Jeśli klasa wykonuje wszystkie jego inicjowania w konstruktorze, a następnie @PostConstruct rzeczywiście jest zbędna.

Jednakże, jeśli klasa ma swoje zależności wstrzyknięte za pomocą metod ustawiających, wówczas konstruktor klasy nie może w pełni zainicjować obiektu, a czasami niektóre inicjacje muszą zostać wykonane po wywołaniu wszystkich metod ustawiających, stąd przypadek użycia @PostConstruct .

+0

@staffman: plus jeden z mojej strony. Jeśli chcę zainicjować pole inputtext z wartością pobraną z bazy danych, mogę to zrobić za pomocą PostConstruct, ale nie uda się, gdy spróbuję zrobić to samo wewnątrz konstruktora. Mam obowiązek inicjowania bez użycia PostContruct. Jeśli masz czas, możesz odpowiedzieć na to również: http://stackoverflow.com/questions/27540573/how-to-initialize-inputtextfield-with-a-value-from-database-on-runtime-without-t –

1

Inicjalizacja oparta na konstruktorze nie będzie działać zgodnie z przeznaczeniem za każdym razem, gdy w grę wchodzi pośredniczenie lub przekazywanie.

CT dostanie nazywa ilekroć EJB dostaje rozszeregować, a gdy nowy pełnomocnik zostanie stworzony dla niego ...

50

innych odpowiedzi, zwłaszcza @ Bozho jedna, już wyjaśniono główną problemu (wśród innymi):

w konstruktorze, zastrzyk z zależnościami jeszcze nie nastąpiło.

W przypadku gdy ktoś nadal mają wątpliwości, co to oznacza, że ​​jest to prawdziwy przykład świat akurat mnie:

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

nadzieję, że pomoże.

+4

'w konstruktorze, zastrzyk zależności jeszcze się nie pojawił. 'prawda z ustawiaczem lub polem wtrysku, ale nie jest prawdą w przypadku wtrysku konstruktora. –

+0

Pewnie! Z ledwością uważam to za * wstrzyknięcie *, chociaż pomimo nazwy, w końcu to tylko przekazywanie parametrów ... ale dzięki za wskazanie tego, –

+0

co z Ejbs? jak ejbUs = (UsEjbBeanRemote) sl.findServiceRemote ("Użytkownik"); ? , Myślę, że zostały zainicjowane w konstruktorze –

2

Rozważmy następujący scenariusz:

public class Car { 
    @Inject 
    private Engine engine; 

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

Od samochodów musi być instancja przed wstrzyknięciem pola, silnik punkt wtrysku jest jeszcze zerowa podczas wykonywania konstruktora, w wyniku NullPointerException.

Ten problem można rozwiązać za pomocą JSR-330 Dependency Injection for Java wstrzyknięcia konstruktora lub wspólnych opisów JSR 250 dla adnotacji metody Java @PostConstruct.

@PostConstruct

JSR-250 tworzy wspólny zestaw opisów, przewidziany Java SE 6.

PostConstruct adnotacja jest używana w sposób, który musi być wykonany po zależność wtrysk odbywa się wykonywać żadnych inicjalizacji. Ta metoda MUSI zostać wywołana zanim klasa zostanie umieszczona w serwisie jako . Ta adnotacja MUSI być obsługiwana we wszystkich klasach, które obsługują wtrysk zależności od obsługi.

JSR-250 Rozdz. 2,5 javax.annotation.PostConstruct

@PostConstruct Adnotacja pozwala na określenie metod być wykonane po przykład został załadowany i wszystkie wtryskuje zostały przeprowadzone.

public class Car { 
    @Inject 
    private Engine engine; 

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

Zamiast wykonywać inicjalizację w konstruktorze, kod jest przenoszony do metody opatrzonej adnotacją @PostConstruct.

Przetwarzanie metod post-konstruktowych jest prostą sprawą znalezienia wszystkich metod opatrzonych adnotacją @PostConstruct i ich wywoływaniem 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); 
     } 
     }); 
} 

Po wykonaniu instancji i wstrzyknięciu należy wykonać przetwarzanie metod postkonstrukcyjnych.