J'ai une classe qui ressemble à ceci:
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
}
Il sert d'objet de configuration globale pouvant être défini au démarrage de l'application, puis utilisé par des dizaines de classes au cours du projet:
// 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
}
}
J'importe maintenant ce code dans un projet Spring et j'essaie de configurer mon Sprinig XML (beans). Je suppose que je pourrais définir un haricot Configurator
solitaire comme suit (ou quelque chose de similaire):
<bean id="configurator" class="com.me.myapp.Configurator" scope="singleton">
<property name="maxRange" value="30"/>
<!-- etc., for all properties -->
</bean>
Ainsi, lorsque WidgetFactory#doSomething
sera exécuté, Spring aura déjà chargé la classe Configurator
et l’a configurée à l’avance.
Est-il correct de définir le scope="singleton"
ou est-ce que cela n'a pas d'importance? Est-ce que je configure correctement les propriétés statiques? Y at-il autre chose que je dois faire ou considérer ici? Merci d'avance.
Il existe certaines différences entre Singleton en tant que modèle de conception et les installations de Spring de Singleton. Singleton, en tant que modèle de conception, garantit que vous avez défini un objet de classe par chargeur de classe. L'installation singleton de Spring (et son approche), en revanche, définiront une instance par contexte Spring.
Dans ce cas, vous pouvez utiliser votre méthode getInstance()
à utiliser par Spring pour saisir votre instance d'objet:
<bean id="configurator" class="com.me.myapp.Configurator" factory-method="getInstance">
</bean>
Avec Spring, la portée du bean singleton
est la valeur par défaut; vous n'avez donc pas besoin de la définir.
Si vous voulez utiliser configurator
comme bean Spring, vous devrez l'injecter dans d'autres objets et non utiliser getInstance()
pour le récupérer. Donc, dans d’autres beans Spring, utilisez @Autowired ou définissez une référence à bean via un fichier xml. Si vous ne réorganisez pas l'utilisation de configurator
dans d'autres classes, il n'y aura aucune différence, Spring instanciera votre classe, mais vous l'utiliserez comme auparavant.
J'ai aussi vu que vous avez une erreur dans la conception de votre singleton. Votre méthode getInstance()
doit être publique et les autres méthodes ne doivent pas être statiques. Dans l'exemple que vous avez utilisé, vous devriez utiliser Singleton comme ceci:
Configurator.getInstance().someMethod()
Dans ce cas, vous utilisez simplement la classe Singleton, sans instancier d'objets! Voir wikipedia sur Singleton (avec l'exemple de Java) pour plus d'informations sur le modèle de conception Singleton et sur son utilisation.
Configurator
comme Singleton et d'utiliser les fonctions de singleton de Spring. Si vous faites cela, les avantages seront que vous pouvezgetInstance()
Les haricots sont singleton par défaut. Vous pouvez trouver cela/plus d'informations sur le site Web du printemps.
Vous ne devez pas instancier un nouveau configurateur dans getInstance car il ne fera pas référence au bean chargé par ressort, ce qui pourrait entraîner des problèmes graves. Vous pouvez câbler ce haricot et le laisser ensuite, il ne sera pas nul parce que vous l'avez câblé (et si c'est votre programme, l'initialisation a échoué).
Oui, si vous voulez quelque chose de global, singleton scope est la bonne option. Voici quelques points qui méritent d’être mentionnés:
Au fait: ce n'est pas thread-safe:
if(INSTANCE == null)
return new Configurator();
return INSTANCE;
}
Considérant que ce serait:
private static Configurator INSTANCE = new Configurator();
(Initialisation désirée)
private static volatile Singleton _instance = null;
(Initialisation paresseuse avec mot clé volatile)
Cela concerne la façon dont Java alloue de la mémoire et crée des instances. Ce n'est pas atomique, mais fait en deux étapes et peut être interféré par le planificateur de thread.
Voir aussi http://regrecall.blogspot.de/2012/05/Java-singleton-pattern-thread-safe.html .