2013-02-01 15 views
10

ho una classe che assomiglia così:Primavera iniezione di una statica Singleton (globale)

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 
} 

Serve come un oggetto di configurazione globale che può essere impostata all'avvio app, e poi viene utilizzato da decine di classi tutto il progetto:

// 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 
    } 
} 

ora sto importando questo codice in un progetto di primavera, e sto cercando di configurare il mio XML Sprinig (fagioli). La mia ipotesi è che potrei definire un solitario Configurator fagiolo in questo modo (o qualcosa di simile):

<bean id="configurator" class="com.me.myapp.Configurator" scope="singleton"> 
    <property name="maxRange" value="30"/> 
    <!-- etc., for all properties --> 
</bean> 

questo modo, quando WidgetFactory#doSomething esegue, Primavera avranno già caricato la classe Configurator e configurato prima del tempo.

È corretto impostare scope="singleton" o non importa? Sto impostando correttamente le proprietà statiche? C'è qualcos'altro che devo fare o considerare qui? Grazie in anticipo.

risposta

7

Ci sono alcune differenze tra Singleton come modello di design e la struttura singleton di Spring. Singleton come modello di progettazione assicurerà che un oggetto della classe definito per Class Loader. L'impianto singleton di Spring (e l'approccio), al contrario, definirà un'istanza per Spring Context.

In questo caso è possibile utilizzare il metodo di getInstance() da utilizzare entro la primavera di afferrare la vostra istanza di oggetto:

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

Con primavera la portata di fagioli singleton è l'impostazione predefinita, pertanto non è necessario definirlo.

Se si desidera utilizzare configurator come bean Spring, è necessario inserirlo in altri oggetti, non utilizzare getInstance() per afferrarlo. Quindi in altri bean Spring usa @Autowired o definisci il riferimento a bean attraverso il file xml. Se non riorganizzi l'uso di configurator in altre classi, non ci saranno differenze, Spring istanzia la tua classe, ma la userai come prima.

Inoltre ho visto che si è verificato un errore nel progettare il proprio singleton. Il tuo metodo getInstance() dovrebbe essere pubblico e altri metodi non dovrebbero essere statici. Nell'esempio che hai usato si dovrebbe usare Singleton in questo modo:

Configurator.getInstance().someMethod() 

In questo caso è in realtà solo utilizzare la classe Singleton, senza istanziare oggetti! Vedere wikipedia on Singleton (with Java example) per ulteriori informazioni sul modello di progettazione Singleton e su come utilizzarlo.


NOTA: vale la pena conoscere e tentare di utilizzare Configurator come Singleton e utilizzare la funzione Singleton di Spring. Se si esegue questa operazione i benefici saranno che si può

  • Rimuovere il metodo getInstance()
  • Fai la tua costruttore pubblico
  • Lasciate che la primavera istanziare quel singolo oggetto.
+0

Grazie @partlov (+1) - avrei bisogno di rendere pubblico il mio metodo 'getInstance()', oppure Spring può gestire il fatto che è privato? –

+0

Non ne hai bisogno (getInstance()) –

1

I fagioli sono singleton per impostazione predefinita. Puoi trovare questa/più informazioni attraverso il sito web di primavera.

Non è necessario creare un'istanza di un nuovo configuratore in getInstance perché non si riferirà al bean caricato a molla e ciò potrebbe causare alcuni problemi gravi. Puoi collegare questo bean e lasciarlo da solo, non sarà nullo perché lo hai cablato (e se il tuo programma avrà fallito l'inizializzazione).

0

Sì, se si desidera qualcosa di globale, l'ambito Singleton è l'opzione giusta. alcune cose vale la pena menzionare qui sono:

  1. L'ambito predefinito in primavera è Singleton, quindi non c'è bisogno di impostare in modo esplicito il bean come ambito Singleton.
  2. Utilizzo di Spring non è necessario scrivere Singleton pattern codice di stile, ad esempio istanze private e metodi factory. Questo perché Spring fornirà che esiste una sola istanza per contenitore Spring . Nemmeno per dire, il tuo metodo di fabbrica è privato.
0

A proposito: questo non è thread-safe:

if(INSTANCE == null) 
     return new Configurator(); 

    return INSTANCE; 
} 

considerando che tale sarebbe:

private static Configurator INSTANCE = new Configurator(); 

(inizializzazione Desideroso)

private static volatile Singleton _instance = null; 

(inizializzazione differita con parola chiave volatile)

Ha a che fare con il modo in cui Java alloca Memoria e crea istanze. Questo non è atomico, ma fatto in due passaggi e può essere interferito dal programmatore di thread.

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

Problemi correlati