2013-02-01 10 views
10

Mam klasy, który wygląda tak:Wiosna wstrzykiwanie statycznym (globalne) 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 
} 

Służy jako obiekt konfiguracji globalnej, który można ustawić na app uruchamiania, a następnie jest wykorzystywany przez dziesiątki klas w całym projekcie:

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

Teraz importuję ten kod do projektu wiosennego i próbuję skonfigurować mój Sprinig XML (komponenty bean). Domyślam się, że mogę określić samotnego Configurator podobnie jak fasola (lub coś podobnego):

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

ten sposób, kiedy WidgetFactory#doSomething Wykonuje, wiosna będzie już załadowany klasę Configurator i ustawił go przed czasem.

Czy to jest właściwe dla mnie ustawić scope="singleton", czy to nie ma znaczenia? Czy prawidłowo ustawiam właściwości statyczne? Czy jest coś jeszcze, co muszę zrobić lub rozważyć tutaj? Z góry dziękuję.

Odpowiedz

7

Istnieje pewna różnica między Singleton jako wzorzec projektu i obiekt singleton Spring. Singleton jako wzorzec projektowy zapewni, że zdefiniowany zostanie jeden obiekt klasy na klasę ładującą. Natomiast w przypadku singleton (i podejścia) Spring zdefiniuje jedną instancję na kontekst wiosny.

W tym przypadku można wykorzystać metodę getInstance() być wykorzystywane przez wiosnę chwycić instancję obiektu:

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

ze sprężyną zakres fasola singleton jest domyślnym dlatego nie trzeba go zdefiniować.

Jeśli chcesz użyć configurator jako fasoli Spring, będziesz musiał wstrzyknąć ją w inne obiekty, a nie używać getInstance(), aby ją pobrać. Tak więc w innych wiosennych ziarnach używaj @Aemowired lub określ odniesienie do fasoli przez plik xml. Jeśli nie zreorganizujesz korzystania z configurator w innych klasach, nie będzie różnicy, Spring stworzy instancję klasy, ale użyjesz jej jak poprzednio.

Widziałem również błąd w projektowaniu singletonu. Twoja metoda getInstance() powinna być publiczna, a inne metody nie powinny być statyczne. W przykładzie użyłeś należy użyć Singleton tak:

Configurator.getInstance().someMethod() 

w tym przypadku właściwie tylko użyć klasy Singleton, bez instancji żadnych przedmiotów! Aby uzyskać więcej informacji na temat wzoru projektu Singleton i sposobu korzystania z niego, zobacz numer wikipedia on Singleton (with Java example).


UWAGA: Warto znać i próbować użyć Configurator jako Singleton i skorzystać z usługi singleton Spring. Jeśli zrobisz to korzyści będzie, że można

  • Usuń metodę getInstance()
  • Dodać konstruktor publiczny
  • Niech Wiosna instancji, że jeden obiekt.
+0

Dzięki @partlov (+1) - czy muszę podać publicznie moją metodę 'getInstance()', czy też Spring może poradzić sobie z faktem, że jest ona prywatna? –

+0

Nie potrzebujesz tego (getInstance()) –

1

Domyślnie fasola jest pojedyncza. Możesz znaleźć te/więcej informacji na stronie internetowej wiosennej.

Nie powinieneś tworzyć nowego konfiguratora w getInstance, ponieważ nie będzie on odnosił się do sprężynowego fasoli, co może powodować poważne problemy. Możesz podłączyć tę fasolę, a następnie zostawić ją w spokoju, nie będzie to wartość zerowa, ponieważ podłączyłeś ją (a jeśli twój program nie będzie w stanie zainicjować).

0

Tak, jeśli chcesz coś globalnego, zakres singleton jest właściwą opcją. kilka rzeczy, warto wspomnieć tutaj:

  1. Domyślny zakres wiosną jest Singleton, dzięki czemu nie trzeba jawnie ustawić zakres fasoli jako singleton.
  2. Korzystając ze sprężyny, nie trzeba pisać Kod stylu Singleton, taki jak prywatne instancje i metody fabryczne. Dzieje się tak dlatego, że Spring będzie zagwarantować, że istnieje tylko jedna instancja na kontener Spring . Nawet nie można powiedzieć, że twoja metoda fabryczna jest prywatna.
0

Nawiasem mówiąc: nie jest bezpieczny wątku:

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

    return INSTANCE; 
} 

O ile będzie to:

private static Configurator INSTANCE = new Configurator(); 

(Marzą inicjalizacji)

private static volatile Singleton _instance = null; 

(inicjalizacji Lazy ze zmiennym słowem kluczowym)

Ma to związek ze sposobem, w jaki Java przydziela pamięć i tworzy wystąpienia. Nie jest to atom, ale jest wykonywane w dwóch etapach i może być zakłócane przez program planujący wątek.

Zobacz także http://regrecall.blogspot.de/2012/05/java-singleton-pattern-thread-safe.html.