2013-02-01 3 views
10

J'ai une classe qui ressemble à ceci:printemps injection statique (global) singleton

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 un objet de configuration globale qui peut être réglé au démarrage de l'application, puis est utilisé par des dizaines de classes tout au long 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 de printemps, et essaie de configurer mon XML Sprinig (haricots). Je suppose que je pourrais définir un haricot Configurator seul comme si (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> 

De cette façon, quand WidgetFactory#doSomething exécute, le printemps sera déjà chargé la classe Configurator et configurée à l'avance.

Est-il exact pour moi de régler l'scope="singleton", ou ce ne est pas grave? Est-ce que je règle les propriétés statiques correctement? Y a-t-il autre chose que je dois faire ou considérer ici? Merci d'avance.

Répondre

7

Il existe une certaine différence entre Singleton en tant que motif de conception et l'installation singleton de Spring. Singleton en tant que motif de conception vous assurera que vous avez un objet de classe défini par Class Loader. En revanche, l'installation singleton de Spring (et son approche) définira une instance par Spring Context.

Dans ce cas, vous pouvez utiliser votre méthode getInstance() à utiliser au printemps pour saisir votre instance d'objet:

<bean id="configurator" class="com.me.myapp.Configurator" factory-method="getInstance"> 
</bean> 

avec ressort le champ de haricot singleton est la valeur par défaut Par conséquent, vous n'avez pas besoin de le définir.

Si vous voulez utiliser configurator comme un haricot de printemps, vous devrez l'injecter dans d'autres objets, ne pas utiliser getInstance() pour l'attraper. Ainsi, dans les autres beans de printemps, utilisez @Autowired ou définissez la référence au bean via le 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 devez utiliser Singleton comme ceci:

Configurator.getInstance().someMethod() 

Dans ce cas, vous fait juste utiliser la classe Singleton, sans instanciation des objets! Voir wikipedia on Singleton (with Java example) pour plus d'informations sur le motif de conception Singleton et comment l'utiliser. REMARQUE: Il est utile de connaître et d'essayer d'utiliser Configurator en tant que singleton et d'utiliser la fonction singleton de Spring. Si vous faites cela, les avantages seront que vous pouvez

  • Retirez la méthode getInstance()
  • Faites votre constructeur public
  • Laissez le printemps instancier ce seul objet.
+0

Merci @partlov (+1) - aurais-je besoin de rendre publique ma méthode 'getInstance()', ou Spring peut-il gérer le fait qu'elle soit privée? –

+0

Vous n'en avez pas besoin (getInstance()) –

1

Les haricots sont singleton par défaut. Vous pouvez trouver cette/plus d'informations sur le site Web du printemps.

Vous ne devriez pas instancier un nouveau configurateur en getInstance, car il ne fera pas référence à la fève de ressort et qui pourrait causer des problèmes graves. Vous pouvez câbler ce bean et le laisser seul, il ne sera pas nul parce que vous l'avez câblé (et si votre programme a échoué lors de l'initialisation).

0

Oui, si vous voulez quelque chose de portée globale, singleton est la bonne option. quelques choses méritent d'être mentionnées ici sont:

  1. La portée par défaut au printemps est singleton, de sorte que vous ne avez pas besoin de définir explicitement bean comme champ singleton.
  2. Utiliser Spring vous n'avez pas besoin d'écrire Singleton modèle code de style, tels que des cas particuliers et une méthodes d'usine. C'est parce que Spring garantit qu'il n'y a qu'une seule instance par conteneur de printemps. Même pas à dire, votre méthode d'usine est privée.
0

Par ailleurs: 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ésireuse)

private static volatile Singleton _instance = null; 

(initialisation Lazy avec mot-clé volatile)

Cela a à voir avec la façon dont Java alloue la mémoire et crée des instances. Ce n'est pas atomique, mais effectué en deux étapes et peut être interféré par le planificateur de threads.

Voir aussi http://regrecall.blogspot.de/2012/05/java-singleton-pattern-thread-safe.html.

Questions connexes