Ich habe eine Klasse, die so aussieht:
public class Configurator {
private static Configurator INSTANCE = null;
private int maxRange = 1;
// many other properties; each property has a default value
private static synchronized Configurator getInstance() {
if(INSTANCE == null)
return new Configurator();
return INSTANCE;
}
public static int getMaxRange() {
getInstance().maxRange;
}
public static void setMaxRange(int range) {
getInstance().maxRange = range;
}
// Getters and setters for all properties follow this pattern
}
Es dient als globales Konfigurationsobjekt, das beim Start der App festgelegt werden kann, und wird dann von Dutzenden von Klassen im gesamten Projekt verwendet:
// Called at app startup to configure everything
public class AppRunner {
Configurator.setMaxRange(30);
}
// Example of Configurator being used by another class
public class WidgetFactory {
public void doSomething() {
if(Configurator.getMaxRange() < 50)
// do A
else
// do B
}
}
Ich importiere diesen Code jetzt in ein Spring-Projekt und versuche, meine Sprinig-XML (Beans) zu konfigurieren. Meine Vermutung ist, dass ich eine einsame Configurator
-Bean wie (oder ähnliches) definieren könnte:
<bean id="configurator" class="com.me.myapp.Configurator" scope="singleton">
<property name="maxRange" value="30"/>
<!-- etc., for all properties -->
</bean>
Auf diese Weise hat Spring, wenn WidgetFactory#doSomething
ausgeführt wird, die Configurator
-Klasse bereits geladen und zuvor konfiguriert.
Ist es richtig für mich, den scope="singleton"
einzustellen, oder spielt dies keine Rolle? Stelle ich die statischen Eigenschaften richtig ein? Gibt es noch etwas, was ich hier tun oder in Betracht ziehen muss? Danke im Voraus.
Es gibt einige Unterschiede zwischen Singleton als Designmuster und der Singleton-Einrichtung von Spring. Singleton als Entwurfsmuster stellt sicher, dass Sie pro Klassenlader ein Klassenobjekt definieren. Im Gegensatz dazu definiert Spring's Singleton-Funktion (und -Ansatz) eine Instanz pro Spring Context.
In diesem Fall können Sie Ihre getInstance()
-Methode verwenden, um von Spring zum Abrufen Ihrer Objektinstanz verwendet zu werden:
<bean id="configurator" class="com.me.myapp.Configurator" factory-method="getInstance">
</bean>
Bei Spring ist der Bereich singleton
bean die Standardeinstellung, daher müssen Sie ihn nicht definieren.
Wenn Sie configurator
als Spring-Bean verwenden möchten, müssen Sie sie in andere Objekte einfügen. Verwenden Sie nicht getInstance()
, um sie zu packen. Verwenden Sie also in anderen Spring-Beans @Autowired oder definieren Sie den Verweis auf die Bean durch die XML-Datei. Wenn Sie die Verwendung von configurator
in anderen Klassen nicht neu organisieren, wird es keinen Unterschied geben. Spring wird Ihre Klasse instanziieren, aber Sie werden sie wie zuvor verwenden.
Ich habe auch gesehen, dass Sie beim Design Ihres Singleton einen Fehler haben. Ihre getInstance()
-Methode sollte öffentlich sein und andere Methoden sollten nicht statisch sein. In dem von Ihnen verwendeten Beispiel sollten Sie Singleton folgendermaßen verwenden:
Configurator.getInstance().someMethod()
In diesem Fall verwenden Sie einfach die Singleton-Klasse, ohne Objekte zu instantiieren! Weitere Informationen zum Singleton-Entwurfsmuster und seiner Verwendung finden Sie unter wikipedia zu Singleton (mit Java-Beispiel) .
Configurator
als Singleton zu verwenden und Spring's Singleton-Funktion zu nutzen. Wenn Sie dies tun, werden die Vorteile sein, die Sie könnengetInstance()
-Methode Beans sind standardmäßig Singleton. Diese/weitere Informationen finden Sie auf der Spring-Website.
Sie sollten einen neuen Configurator in getInstance nicht instanziieren, da er sich nicht auf die federbelastete Bean bezieht und dies zu ernsthaften Problemen führen kann. Sie können diese Bean anschliessen und sie dann in Ruhe lassen. Sie wird nicht null sein, da Sie sie verdrahtet haben (und wenn dies der Fall ist, ist Ihr Programm nicht initialisiert worden).
Ja, wenn Sie etwas globales wollen, ist der Singleton-Bereich die richtige Option. Ein paar erwähnenswerte Dinge sind hier:
Übrigens: das ist nicht Thread-sicher:
if(INSTANCE == null)
return new Configurator();
return INSTANCE;
}
Während dies wäre:
private static Configurator INSTANCE = new Configurator();
(Eifrige Initialisierung)
private static volatile Singleton _instance = null;
(Faule Initialisierung mit volatilem Schlüsselwort)
Es hat damit zu tun, wie Java Speicher zuordnet und Instanzen erstellt. Dies ist nicht atomar, sondern erfolgt in zwei Schritten und kann vom Thread-Scheduler gestört werden.
Siehe auch http://regrecall.blogspot.de/2012/05/Java-singleton-pattern-thread-safe.html .