Blog

Abhilfe der Konfigurationshölle mit Singleton-Injektion

Urs Peter

Urs Peter

Aktualisiert Oktober 23, 2025
6 Minuten
Eine der am häufigsten gehörten Beschwerden über Spring-Projekte ist die scheinbar unvermeidliche Konfigurationshölle, die sich in jedem größeren Projekt nach einiger Zeit einschleicht. Singleton Injection ist eine einfache Praxis, die die Konfiguration und den entsprechenden Injektionscode erheblich reduzieren kann. Außerdem bietet sie Möglichkeiten, die Sie vielleicht noch nicht kannten, so dass Sie das Beste aus Spring herausholen können. In diesem Blog erfahren Sie, welche Vorteile Singleton Injection bietet. Er veranschaulicht, wie man sie implementiert und gibt klare Richtlinien vor, unter welchen Umständen sie am besten angewendet wird. Wo es anwendbar ist, kann Singleton Injection eine elegante Lösung sein, die den Code und die Konfiguration erheblich vereinfacht. Zu Beginn eines Spring-Projekts, wenn die applicationContext.xml(s) einem brachliegenden Feld ähneln, ist es einfach, den Überblick über Ihre Beans zu behalten. Mit der Zeit sind die meisten von uns damit konfrontiert, dass die Konfigurationshölle ins Unermessliche wächst und es schwierig macht, sich im Bean-Dschungel zurechtzufinden. Es gibt mehrere allgemein angewandte Best Practices, um dieses Problem so lange wie möglich hinauszuzögern, wie z.B. die Verwendung von abstrakten Deklarationen, die Aufteilung der Bean-Konfiguration in mehrere Unterkonfigurationen oder die Spring IDE von Eclipse.Daneben bin ich auf eine weitere Möglichkeit gestoßen, die erheblich dazu beitragen kann, die Spring-Konfiguration zu reduzieren, überflüssigen Code zu eliminieren und weitere interessante Vorteile zu bieten, die Ihnen vielleicht vorher nicht bewusst waren. Der Weg dorthin heißt Singleton Injection.

Der vertraute Weg

Betrachten Sie das folgende Stück Code und die Konfiguration: [java] public class AnyService { private Logger log = Logger.getLogger(AnyService.class); private MessageResource messageResouce; public setMessageResource(MessageResource messageResouce) { this.messageResouce = messageResouce; } public void execute() { if(Bedingung) log.error(messageResource.getMessage("error.msg.key.1")); // mehr Code } } public class AnyDAO { private Logger log = Logger.getLogger(AnyDAO.class); private MessageResource messageResouce; public setMessageResource(MessageResource messageResouce) { this.messageResouce = messageResouce; } public List findAll() { if(Bedingung) log.warn(messageResource.getMessage("error.msg.key.2")); //mehr Code } } [/java] [xml] property name="resourceLocation" value="classpath:/bundle.properties"/> [/xml] Offensichtlich wird die Klasse MessageResource in der gesamten Anwendung verwendet, und zwar von jeder Klasse, die etwas protokollieren muss. Da wir die MessageResource-Klasse mit der richtigen Konfiguration über die BeanFactory-Funktionen initialisieren wollen, konfigurieren wir die MessageResource-Klasse als Spring Bean und injizieren sie in jede Klasse, die sie verwendet. Danach folgt ein mühsamer Code für Instanzvariablen/Setter und die Injektionskonfiguration. Dies sollte Ihnen bekannt vorkommen.

Die Alternative: Singleton Injektion

Zum Glück gibt es einen einfacheren Weg. Betrachten Sie das folgende Stück Code: [java] public class AnyService { private Logger log = Logger.getLogger(AnyService.class); public void execute() { if(condition) Log.error(MessageResourceSingleton.getInstance().getMessage("error.msg.key.1")); // mehr Code } } [/java] Wie Sie sehen, scheint der größte Teil des mit Spring verbundenen Injektionsaufwands verschwunden zu sein. Zumindest könnte das der erste Eindruck sein. Anstatt die MessageResource-Bean umständlich in alle Klassen zu injizieren, die sie verwenden, wählen wir einen etwas anderen Ansatz: 1. Wir schreiben eine Wrapper-Klasse, die das Singleton-Muster anwendet (hier MessageResourceSingleton) und eine Implementierung der MessageResource-Klasse umhüllt 2. Fügen Sie dann eine Konfiguration hinzu, die die Implementierung (MessageResource) in den Singleton-Wrapper (MessageResourceSingleton) injiziert Der folgende Code und die Konfiguration veranschaulichen den Singleton-Injektionsansatz: [java] public class MessageResourceSingleton implements MessageResource{ /** MessageResource-Implementierung, die injiziert werden soll */ private MessageResource messageResource; /** Singleton-Instanz */ private static MessageResourceSingleton singleton = new MessageResourceSingleton(); /** * Ruft das Singleton ab * @return singleton */ public static MessageResourceSingleton getInstance(){ return singleton; } /** * Setter für die MessageResource-Implementierung, die zur Injektion verwendet wird * die Implementierung * @param messageResource */ public void setMessageResource(MessageResource messageResource) { this.messageResource = messageResource; } /** * Delegiert den Aufruf an die injizierte Implementierung * @param args Argumente * @return message */ public String getMessage(String key) { return messageResource.getMessage(key); } } [/java] [xml] [/xml] Jede Klasse, die die MessageResource-Implementierung verwenden möchte, ruft einfach auf: [java] MessageResourceSingleton.getInstance().getMessage("any.key"); [/java] Auf diese Weise können wir alle Konfigurationsmöglichkeiten nutzen, die Spring bei der Definition der Implementierungs-Bean bietet. Der Code, der die Implementierung verwendet, wird nicht nur von überflüssigem Injektionscode und der entsprechenden Konfiguration befreit, sondern weiß - wie es das IoC-Prinzip verlangt - überhaupt nicht, dass Spring die Fäden (oder Beans ;-)) in der Hand hält.

Ihre Gewinne mit Singleton Injection

Wenn Sie also Singleton Injection verwenden, sind das Ihre Vorteile: - Geringere Konfiguration und weniger Code (einmal injizieren und überall verwenden) - Eingespritzte Singletons können in Klassen verwendet werden, die nicht Teil der Beanwiring-Kette sind - Statische Methoden können eingespritzte Singletons verwenden - Eingespritzte Singletons können als Beanwiring-Startpunkte dienen - Erhöhte Produktivität (sofortige Verwendung von eingespritztem Code) Da dies alles so einfach, praktisch und vorteilhaft erscheint, warum sollten Sie Singleton-Injection nicht überall in Ihrem Code verwenden?

Wann Sie die Singleton-Injektion verwenden sollten

Der Kompromiss bei der Singleton-Injektion ist Einfachheit gegenüber Flexibilität. Die Einschränkung besteht darin, dass das Singleton nur eine bestimmte Implementierung umhüllen kann. Daher muss sich jede Klasse, die den Singleton-Wrapper verwendet, an diese bestimmte Implementierung halten. Sie können immer noch mehrere Implementierungen zur Verfügung haben (für Unittesting, Mocking usw.), aber zur Laufzeit kann nur eine davon in der gesamten Anwendung verwendet werden.Mit anderen Worten, wenn Sie mit einem "Einheitsgrößen"-Szenario konfrontiert sind, haben Sie einen Fall für eine Singleton-Injection. Genauer gesagt müssen die folgenden Voraussetzungen erfüllt sein, damit Singleton Injection eine sinnvolle Wahl ist: - Eine Spring Bean wird in verschiedenen, peripheren Teilen der Anwendung verwendet - Eine Spring Bean hat die Eigenschaften einer Utility-Klasse, die mit externen Ressourcen oder anderen Parametern initialisiert werden muss - Auf eine Spring Bean muss von Klassen zugegriffen werden können, die nicht Teil der Beanwiring-Kette sind - Es reicht aus, dass zur Laufzeit nur eine bestimmte Implementierung der Spring Bean in der gesamten Anwendung verwendet wird

Reale Fälle für Singleton Injection

Ich habe Singleton Injection in verschiedenen Projekten eingesetzt. Die folgenden Klassen haben sich als hervorragende Kandidaten für Singleton Injection erwiesen: - MessageResource-Dienstprogramm wie das in diesem Beispiel verwendete - Logger-Dienstprogramm, das die Protokollierung in eine Datenbank oder Warteschlange durchführen muss - IDGenerator, der die für die Protokollierung oder das Messaging verwendeten IDs aus einer Datenbank abruft - CodeMapper, der technische Codes auf eine Beschreibung abbildet - Business Delegate, der als Ausgangspunkt für die Beanwiring-Verdrahtung verwendet werden kann - Jedes Dienstprogramm, das Sie in einem Framework oder einer Komponente verwenden möchten, die keine Hooks für die Injektion von Spring Beans bietet (falls es sie noch gibt...).)

Fazit

Gegebenenfalls kann Singleton Injection eine elegante Lösung sein, die den Code und die Konfiguration erheblich vereinfacht. Außerdem können Sie so von der "Spring Injection Power" außerhalb der Standard-Beanwiring-Kette profitieren. All dies kann mit einer so einfachen Sache wie Singleton Injection erreicht werden. Sie ermöglicht es Ihnen, mit weniger mehr zu erreichen - ist das nicht das, worum es beim Programmieren geht?

Verfasst von

Urs Peter

Contact

Let’s discuss how we can support your journey.