Unterschied zwischen Java Singleton und Spring Singleton

Eines der häufigsten Missverständnisse unter Spring Framework-Entwicklern ist der Unterschied zwischen Spring Singleton und Java Singleton. Interessanterweise ist dies eine der beliebtesten Interviewfragen für Spring-Entwickler, um das Verständnis von Singleton-Konzepten zu überprüfen.

Wenn Sie an Java- und Spring-Technologien arbeiten, ist es sehr wichtig, den klaren Unterschied zwischen Java Singleton und Spring Singleton zu kennen. In diesem Beitrag werde ich den grundlegenden Unterschied zwischen den beiden Singleton-Konzepten erläutern. Wenn Sie mit dem Singleton-Muster noch nicht vertraut sind, lesen Sie bitte unser Tutorial zum Java-Singleton-Muster.

Die Java-Singleton-Klasse ist pro Klassenlader und Springs Singleton ist pro Anwendungskontext.

Java Singleton vs. Spring Singleton

Java-Singleton

Beachten Sie, dass es keine vordefinierten Regeln für die Implementierung der Singleton-Klassen gibt, die Klasse jedoch nur einmal pro Klassenlader instanziiert werden sollte. Hier sind die grundlegenden Schritte zum Implementieren der Java Singleton-Klasse.

  • Wenn Sie von einer Singleton-Klasse sprechen, sollte nur eine Instanz dieser Klasse erstellt werden können.
  • Der Konstruktor dieser Klasse muss privat sein, um eine Instanziierung durch externe Klassen zu vermeiden.
  • Deklarieren Sie eine statische Variable, um die Instanz für diese Klasse zu speichern.
  • Deklarieren Sie eine Methode, die die Instanz dieser Klasse zurückgibt.

Mit den oben genannten Grundregeln kann man die Java-Singleton-Implementierung in die folgenden Kategorien einteilen:

  • Eifrig Initialisierung
  • Statische Blockinitialisierung
  • Verzögerte Initialisierung
  • Threadsicherer Singleton
  • Eifrig Initialisierung

    Bei der Eager-Initialisierung wird die Singleton-Instanz zum Zeitpunkt des Ladens der Klasse erstellt. Dies ist der einfachste Weg, die Singleton-Instanz für Ihre Singleton-Klasse zu erstellen. Der Hauptnachteil dieses Ansatzes besteht jedoch darin, dass die Instanz erstellt wird, obwohl sie von keiner Clientanwendung verwendet wird. Bei diesem Ansatz müssen Sie lediglich eine Instanz in der statischen Variablendeklaration erstellen. Dieser Ansatz bietet keine Option zur Ausnahmebehandlung.

    Hier ist das Beispiel für die Eager-Initialisierung einer Singleton-Instanz:

    public class EagerInitialization {
        private static final EagerInitialization instance = new EagerInitialization();
        private EagerInitialization(){}
        public static EagerInitialization getInstance(){
            return instance;
        }
    }
    

    Statische Blockinitialisierung

    Dies fällt ebenfalls unter die Eager-Initialisierung. Der einzige Unterschied besteht darin, dass die Instanzerstellung innerhalb des statischen Initialisierungsblocks abgeschlossen wird. Dieser Ansatz bietet keine Option zur Ausnahmebehandlung.

    Hier ist das Beispiel für die statische Blockinitialisierung einer Singleton-Instanz:

    public class StaticBlockInitialization { 
        private static StaticBlockInitialization singletonInstance;     
        private StaticBlockInitialization(){}     
        static{
            try{
                singletonInstance = new StaticBlockInitialization();
            }catch(Exception e){
                throw new RuntimeException("Exception occured while creating the singleton instance");
            }
        }     
        public static StaticBlockInitialization getInstance(){
            return singletonInstance;
        }
    }
    

    Verzögerte Initialisierung

    Bei diesem Ansatz erstellen wir die Instanz erst nach dem Laden der Klasse und dem ersten Aufruf der Instanz. Dadurch wird vermieden, dass die Instanz vorab initialisiert wird, wenn Sie die vom Dienst angeforderte Instanz nicht benötigen.

    Dieser Ansatz funktioniert gut, wenn diese Klasse in der Single-Thread-Umgebung ausgeführt wird, aber in der Multi-Thread-Umgebung funktioniert dies nicht gut, wenn mehrere Threads gleichzeitig versuchen, die neue Instanz abzurufen (Lesen Sie: Threading in Java).

    Hier ist das einfache Beispiel für die Java-Singleton-Klasse mit dem Ansatz der verzögerten Initialisierung:

    public class Main {
    	public static void main(String args[]) {
    		Singleton singleton = Singleton.getInstance();
    		System.out.println("Value 1 : " + singleton.getValue());
    		singleton.setValue(20);
    		Singleton singleton2 = Singleton.getInstance();
    		System.out.println("Value 2: " + singleton2.getValue());
    	}
    }
    
    class Singleton {
    	private Singleton() {}
    	private static Singleton singleton;
    	private int value = 10;
    	public static Singleton getInstance() {
    		if (singleton == null) {
    			singleton = new Singleton();
    		}
    		return singleton;
    	}
    	public int getValue() {
    		return value;
    	}
    	public void setValue(int value) {
    		this.value = value;
    	}	
    }
    

    Threadsicherer Singleton

    Dies ähnelt dem oben genannten Ansatz, außer dass die zum Erstellen der Singleton-Instanz verwendete Methode synchronisiert ist. Dieser Ansatz ist die sicherste und beste Lösung zur Implementierung der Singleton-Instanz, bringt jedoch Leistungsprobleme mit sich, wenn mehrere Threads gleichzeitig versuchen, auf die Instanz zuzugreifen.
    Hier ist das Beispiel für eine Thread-sichere Singleton-Instanz:

    public class ThreadSafeInstance { 
        private static ThreadSafeInstance singletonInstance;
        private ThreadSafeInstance(){}
        public static synchronized ThreadSafeInstance getInstance(){
            if(singletonInstance == null){
                singletonInstance = new ThreadSafeInstance();
            }
            return singletonInstance;
        }
    }
    

    Frühlings-Singleton

    Der Umfang des Spring-Singletons lässt sich am besten pro Container und pro Bean beschreiben. Wenn Sie eine Bean für eine bestimmte Klasse in einem einzelnen Container definieren, erstellt der Spring-Container nur eine Instanz für die Klasse. Im Frühjahr wird Singleton als einer der Bereiche zum Definieren der Bohnen bezeichnet. Der Singleton-Bereich ist der Standardbereich für Spring Beans.

    Singleton

    Hier ist die Beispieldeklaration der Singleton-Beans von Spring:

    <bean id="bookService"  />
    <!-- the following is equivalent, though redundant (singleton scope is the default) -->
    <bean id="bookService"   scope="singleton"/>
    

    Wie funktioniert Spring Singleton?

    Wenn Sie an eine Singleton-Instanz denken, ist die erste Frage, die Ihnen in den Sinn kommt, die Thread-Sicherheit Ihrer Anwendung. Die Singleton-Beans von Spring werden von allen Anforderungen gemeinsam genutzt, wenn Ihre Anwendung in der Multithread-Umgebung ausgeführt wird. Wie stellen Sie sicher, dass Ihr Programm threadsicher ist?

    Es ist wichtig zu bedenken, dass Ihre Singleton-Beans keine Statusinformationen speichern sollten. Denn die einmal erstellte Bean-Instanz wird von allen Threads gemeinsam genutzt, die diese Spring Bean anfordern. Wenn Sie ein Objekt in die Singleton-Bean von Spring einfügen, wird es nur einmal verkabelt und nie aktualisiert. Es ist ideal, alle Controller als Singleton-Beans und Wertobjekte als Prototyp-Beans zu erstellen.

    Wenn Sie möchten, dass Ihre Prototyp-Beans jedes Mal injiziert werden, müssen Sie die Methodeninjektion implementieren. Andernfalls gibt es keine Möglichkeit, Ihr Singleton-Objekt dazu zu bringen, die Prototyp-Beans jedes Mal neu zu starten. Bitte lesen Sie mein Tutorial zur Methodeninjektion, um zu verstehen, wie Sie bei jeder Anforderung Wertobjekte instanziieren und in die Singleton-Objekte injizieren.

    Schauen Sie sich diesen Codeausschnitt an:

    @Controller
    public class SampleController {
    	int i = 0;
    	@Autowired
    	private ValueObject vo;
    }
    

    Im obigen Codeausschnitt wird ValueObject in den XML-Konfigurationen als Prototyp-Bean deklariert. Dieses Objekt wird jedoch nur einmal eingefügt, wenn die SampleController-Instanz zum ersten Mal erstellt wird. Danach wird für alle Anfragen dasselbe Objekt verwendet. In diesem Fall sollten die Variablen i und vo keine Statusinformationen enthalten, da diese sonst in allen Threads vorhanden sind.

    Wenn beispielsweise die Variable i erhöht wird, indem eine Anforderung an einen anderen Thread weitergegeben wird. Dies führt zu Verwirrung und die Anwendung ist nicht threadsicher. Um dies zu vermeiden, deklarieren Sie keine Instanzvariablen, die die Statusinformationen in Singleton-Beans speichert.

    Zusammenfassung

    Ich hoffe, dass dieser Beitrag die Grundkonzepte hinter Java Singleton und Spring Singleton vermittelt hat. Java-Singleton ist pro Klassenlader und Spring-Singleton ist pro Anwendungskontext für eine Bean. Erfahren Sie außerdem mehr über die unterschiedlichen Geltungsbereiche der Frühlingsbohnen, um zu verstehen, wann Sie die Singleton-Bohnen im Frühling verwenden müssen.

    Kommentar verfassen

    Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

    Nach oben scrollen