2013-02-28 12 views
10

Ich versuche, ein Logger-Objekt in einer Klasse zu injizieren, die nach einem Singleton-Ansatz implementiert wird.Verwenden von CDI in einem Singleton-Muster

Der Code sieht fast wie folgt aus:

Logger Klasse:

public class LoggerFactory { 
    @Produces 
    public Logger getLogger(InjectionPoint caller){ 
     return Logger.getLogger(caller.getMember().getDeclaringClass().getName()); 
    } 
} 

Dann erstelle ich eine Klasse, die Logger und implementiert das Singleton Pattern benötigt:

public class MySingleton{ 
    @Inject 
    private Logger logger; 

    private MySingleton instance; 

    /* 
    * Private constructor for singleton implementation 
    */ 
    private MySingleton(){ 
     logger.info("Creating one and only one instance here!"); 
    } 

    public MySingleton getInstance(){ 

     if(instance == null) { 
      instance = new MySingleton(); 
     } 

     return instance; 
    } 

}

Wenn ich den Code (auf Glassfish 3.1.2.2) ausführen, erhalte ich eine NPE sobald ich versuche den Logger zu benutzen. Was mache ich falsch (beans.xml Datei ist vorhanden)? Ich habe auch versucht, @Inject mit einer Setter-Methode für die Logger Objekt, aber ohne Glück.

+6

Injektionen geschieht nach dem Konstrukt. Sie können es also nicht im Konstruktor verwenden. –

+1

Warum verwenden Sie normalerweise einen Singleton anstelle von injetin, wo Sie es brauchen, und CDI machen es zu einem Singleton-Bereich Bohne? –

+0

Ich weiß nicht viel über CDI, aber sollten Sie nicht Ihren Injektor verwenden, um Ihr Objekt zu erstellen? Mit Spring wird die Injektion nur ausgeführt, wenn ein Objekt mit einem Anwendungskontext und mit Guice nur bei Verwendung eines Injektors erstellt wird. –

Antwort

17

Injektionen geschieht nach dem Konstrukt. Sie können es also nicht im Konstruktor verwenden.

Eine Möglichkeit besteht darin, eine mit @PostConstruct annotierte Methode hinzuzufügen, die nach den Injektionen aufgerufen werden kann.

@PostConstruct 
public void init() { 
    logger.info("Creating one and only one instance here!"); 
} 

Auf einer Nebenbemerkung Ich denke, dass Sie das Problem in die falsche Richtung verlegen. CDI hat eine schöne Singletons Unterstützung

eine Klasse erstellen @Singleton kommentierte

@Singleton 
public class MySingleton { 

    @Inject 
    Logger logger; 

    @PostConstruct 
    public void init() { 
     logger.info("Creating one and only one instance here!"); 
    } 

} 

Above Sie CDI verwenden übernimmt für Java EE (JSR-299).

Wenn Sie JSR 330 Dependency Injection verwenden (guice etc.) link

Sie Konstruktor Injektion verwenden:

@Singleton 
public class MySingleton { 


    private final Logger logger; 

    @Inject 
    public MySingleton (Logger logger) { 
     this.logger = logger; 
     logger.info("Creating one and only one instance here!"); 
    } 
} 
+1

Vielen Dank für die Antwort @AkselWillgert, ich ging für die CDI-Implementierung. – fabpicca

+1

Sprechen Sie javax.inject.Singleton oder javax.ejb.Singleton hier? JN01

4

Das wird nicht funktionieren, weil Injektion, wie bereits erwähnt, wird ausgeführt nachdem der Konstruktor aufgerufen wurde.

Methoden, die mit kommentiert wurden, werden aufgerufen, nachdem die Injektion abgeschlossen wurde und bevor das Objekt selbst an anderer Stelle geliefert wird.

Die Injektion funktioniert jedoch nur, wenn die Instanz Ihrer Klasse durch Injektion selbst bereitgestellt wird. Dies liegt an der Injektion abhängig von Proxy.

Daher müssen Sie Ihren MySingleton injizieren, wo immer Sie es brauchen. Um sicher zu sein, dass es ein Singleton ist, notieren Sie es @Singleton und der Container wird das für Sie arbeiten.

Addiotnally passen sie auf, dass Singletons in Bezug auf die CDI-Spezifikation bedeutet nicht nur eine Instanziierung, sondern nur eine initialiation von @PostConstruct.