2010-08-04 6 views
196

In einer verwalteten Bean wird nach dem regulären Java-Objektkonstruktor aufgerufen.Warum @PostConstruct verwenden?

Warum sollte ich initialisieren von Bean anstelle des regulären Konstruktors selbst?

+0

Ich hatte den Eindruck, dass die Konstruktorinjektion im Allgemeinen bevorzugt wurde, damit die Abhängigkeiten "final" sind. Bei diesem Muster wird '@ PostConstruct' zu J2EE hinzugefügt - sie müssen sicherlich einen anderen Anwendungsfall gesehen haben? – mjaggard

Antwort

288
  • Wenn der Konstruktor aufgerufen wird, ist die Bean noch nicht initialisiert - d. H., Keine Abhängigkeiten werden injiziert. In der Methode ist die Bean vollständig initialisiert und Sie können die Abhängigkeiten verwenden.

  • weil dies der Vertrag ist, der garantiert, dass diese Methode nur einmal im Bean-Lebenszyklus aufgerufen wird. Es kann vorkommen (obwohl unwahrscheinlich), dass eine Bean mehrmals vom Container in seiner internen Arbeit instanziiert wird, aber es garantiert, dass nur einmal aufgerufen wird.

+7

für den Fall, dass der Konstruktor selbst alle Abhängigkeiten automatisch steuert - dann kann die Bean auch im Konstruktor vollständig initialisiert werden (nach dem manuellen Einstellen aller autowired Felder). – yair

+3

Was ist der Fall, in dem ein Bean-Konstruktor mehr als einmal aufgerufen werden kann? – yair

+0

Wahrscheinlich so etwas wie "Passivierung". Wenn der Container beschließt, die Bean im Festplattenspeicher zu speichern und von dort aus wiederherzustellen. – Bozho

45

Wenn Ihre Klasse alle seine Initialisierung im Konstruktor führt, dann ist @PostConstruct in der Tat überflüssig.

Wenn jedoch die Abhängigkeiten der Klasse mit Setter-Methoden angegeben werden, kann der Konstruktor der Klasse das Objekt nicht vollständig initialisieren, und manchmal muss nach dem Aufrufen aller Setter-Methoden eine Initialisierung durchgeführt werden, daher der Anwendungsfall .

+0

@staffman: plus eins von meiner Seite. Wenn ich ein Eingabetextfeld mit einem aus der Datenbank abgerufenen Wert initialisieren möchte, kann ich dies mit Hilfe von PostConstruct tun, scheitere jedoch, wenn ich versuche, dasselbe innerhalb des Konstruktors zu tun. Ich habe diese Anforderung ohne die Verwendung von PostConstruct zu initialisieren. Wenn Sie Zeit haben, können Sie diese auch beantworten: http://stackoverflow.com/questions/27540573/how-to-initialize-inputtextfield-with-a-val-from-database-on-runtime-witout-t –

1

Auch die Konstruktor-basierte Initialisierung funktioniert nicht wie beabsichtigt, wenn eine Art von Proxying oder Remoting involviert ist.

Die ct genannt wird erhalten, wenn ein EJB deserialisiert wird, und wann immer ein neuer Proxy wird für sie erstellt ...

50

Die anderen Antworten, vor allem @ Bozho ist ein, erklärt bereits die Haupt Problem (unter der andere):

in einem Konstruktor hat die Injektion der Abhängigkeiten noch nicht stattgefunden.

Falls jemand noch Zweifel, was das bedeutet, ist dies ein Beispiel reale Welt nur mir passiert:

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

Hoffnung, das hilft.

+4

'In einem Konstruktor ist die Injektion der Abhängigkeiten noch nicht aufgetreten. 'stimmt mit Setter- oder Feldinjektion überein, stimmt aber nicht mit der Konstruktorinjektion. –

+0

Sicher! Ich denke kaum über diese * Injektion * nach: trotz des Namens, am Ende ist es nur Parameterübergabe ... aber danke, dass du darauf hingewiesen hast –

+0

was ist mit Ejbs? wie ejbUs = (UsEjbBeanRemote) sl.findServiceRemote ("Benutzer"); ? Ich denke, dass sie im Konstruktor initialisiert wurden –

2

sich das folgende Szenario:

public class Car { 
    @Inject 
    private Engine engine; 

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

Da Car instanziiert Feld vor der Injektion werden muss, ist der Einspritzpunkt Motor während der Ausführung des Konstruktors noch null, in einem Nullpointer führt.

Dieses Problem kann entweder durch JSR-330 Dependency Injection for Java Konstruktorinjektion oder gemeinsame JSR 250-Annotationen für die Annotation der Java @ PostConstruct-Methode gelöst werden.

@PostConstruct

JSR-250 einen gemeinsamen Satz von Anmerkungen definiert, die in Java SE 6 aufgenommen worden ist.

Die PostConstruct Anmerkung wird von einem Verfahren verwendet wird, die ausgeführt werden muss, nachdem Abhängigkeitsinjektion erfolgt jede Initialisierung durchzuführen. Diese Methode MUSS aufgerufen werden, bevor die Klasse in Betrieb genommen wird. Diese Annotation MUSS für alle Klassen unterstützt werden, die die Abhängigkeitsinjektion unterstützen.

JSR-250 Kap. 2.5 javax.annotation.PostConstruct

Die @PostConstruct Annotation ermöglicht die Definition von Verfahren nach der Instanz ausgeführt werden soll instanziiert worden und alle einspritzt durchgeführt wurden.

public class Car { 
    @Inject 
    private Engine engine; 

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

Anstelle der Initialisierung im Konstruktor der Durchführung wird der Code auf ein Verfahren bewegt mit @PostConstruct annotiert.

Die Verarbeitung von Post-Construct-Methoden ist eine einfache Angelegenheit, alle mit @PostConstruct annotierten Methoden zu finden und diese wiederum aufzurufen.

Die Verarbeitung von Post-Construct-Methoden muss nach der Instantiierung und Injektion durchgeführt werden.