Spring Bean Instanzierung – wenn ein Singleton kein Singleton mehr ist

Der Anwendungsfall:

Ich möchte eine Klasse z.B. PropertyRepository (als Singleton implementiert) mittels des MBeanExporters von Spring als MBean exportieren. So kann man dann zum Beispiel mit Hilfe der jconsole diese Klasse managen.
Damit der MBeanExporter diese Klasse kennt, muss sie im applicationContext als bean gemapped sein (auch die Klasse eigentlich kein „Bean“ ist !) :

Die klassische Singleton Implementation sieht ja wie folgt aus:

private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}return instance;
}

Wobei eine Instanz der Klasse nur über die statische getInstance() Methode geholt werden kann:

Singleton s = Singleton.getInstance();

Innerhalb der getInstance() Methode wird dann ggf. der private Konstruktor aufgerufen um eine Instanz der Klasse zu erzeugen und dem statischen Feld instance zugewiesen.
Der private Konstruktor kann also nur innerhalb der getInstance() Methode aufgerufen werden. So ist sichergestellt, das man es immer mit der selben Instanz zu tun hat. Sollte man meinen.
Da die Klasse aber im Spring applicationContext als bean gemapped ist, instanziert Spring beim Start alle Klassen, die gemapped sind. Hierbei wird auch der private Konstruktor unseres Singleton aufgerufen!
Das führt dazu, das bereits eine Instanz der Klasse erzeugt wird, das statische Feld instance aber immer noch null ist.
Dies führt wiederum dazu, das beim Aufruf von getInstance() die Abfrage : if (instance == null) zu true evaluiert und eine weitere Instanz erzeugt wird.
Jetzt wird diese Instanz auf dem statischen Feld instance zugewiesen. Man bekommt also genau 2 Instanzen des Singletons !

Der Hack um das oben beschriebene Verfahren („MBean Export über beanmapping“) trotzdem zu verwenden ist:

Man weist die durch den privaten Konstruktor erzeugte Instanz der Klasse noch im Konstruktor der Feld inctance zu:

private Singleton(){
instance = this;
}
So ist das Feld instance nicht null und es wird auch in getInstance() immer das selbe Objekt zurückgegeben – hoffentlich :)

5 Responses to “Spring Bean Instanzierung – wenn ein Singleton kein Singleton mehr ist”

  1. 6. Juli 2007 at 11:52 #

    und was ist bei concurrent access aus verschiedenen threads? Korrekterweise muss da ein locking hin, und bitte immer daran denken: double checked locking is broken!

    http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

    gruss dirk

  2. stephan
    6. Juli 2007 at 13:25 #

    I know – das ist ja noch mal ein ganz anderes Thema kann man sogar schon sehen wenn man eine dual-core cpu hat und mal auf ein „Singelton“ zugreift.
    Dazu aber später mehr

  3. 9. Juli 2007 at 9:39 #

    spring sieht für den fall eines singletons folgende konfiguration vor:

    grüße
    steffen

  4. Steffen
    9. Juli 2007 at 21:18 #

    so zweiter versuch mit kommentar ohne xml :)

    spring bietet die möglichkeit beans „lazy“ zu laden, mit:

    bean id=“lazy“ class=“com.foo.ExpensiveToCreateBean“ lazy-init=“true“

    lässt sich das instanzieren in den application context zur startzeit verhindern.

    http://static.springframework.org/spring/docs/2.0.x/reference/beans.html#beans-factory-lazy-init

  5. stephan
    9. Juli 2007 at 21:26 #

    ahh cool Danke

    .. is trotzdem nen netter Hack :)

Leave a Reply