Hallo Oliver,
ok vorab - vielen vielen Dank für diese ausführliche Antwort, damit habe ich ehrlich gesagt nicht gerechnet
Jetzt möchte ich auch gerne auf Deinen Text eingehen:
Hehe, die Frage gehört in die "Most frequent mistakes mit Spring". Ein AC ist nie Singleton. Schon allein um genau diese Art des Zugriffs zu verhindern. Spring ist u.A. auch angetreten um Dependencies durch Factorymethoden
(...)
zu verhindern. Diese sorgen für faktische Untestbarkeit der Klasse, in der dieser Code steht, da du die Implementierung nicht ohne weiteres austauschen kannst.
Gut, das sehe ich ein. Ich habe mir schon gedacht, dass diese Frage ziemlich vielen im Kopf herum geht, die Spring noch nicht verstanden haben. Aber ich denke, ich habe das Konzept mitlerweile verstanden, warum ich diese Singleton Sache trotzdem haben wollte, erkläre ich weiter unten.
Dröseln wir es doch mal von unten auf. Du benötigst eine Dependency zum ApplicationContext.
Dachte ich jedenfalls... wie gesagt weiter unten schreibe ich Dir, worum es mir geht.
1. Dependencies zu technischen Klassen sollten wohl überlegt sein. Warum brauchst du die, was willst du mit dem AC anstellen? Bietet Spring für das was du anstellen willst, evtl einen anderen (besseren) Weg?
Ich hoffe sehr, dass Du mir das gleich sagen kannst
Eine Dependency zu einer Frameworkklasse macht deine Klasse eigentlich auch zu einem Teil des Frameworks. Zumindest zu einer Klasse, die mit geschäftlicher Logik nicht viel zu tun haben sollte. Die Frage ist dabei dann nämlich: Wie kannst du die Klasse noch (möglichst ohne das Framework selbst) testen?
Ah, gute Gedanken - nein ich möchte meine Klasse eigentlich nur sehr ungern von Spring abhängig machen.
Oft sind Entwickler der Meinung Komponenten selbst aus dem AC auslesen zu müssen. getBean sollte möglichst gar nicht gerufen werden. Dafür gibt es DependencyInjection.
Ok - verstehe ich.
2. Wenn du beschlossen hast, dass eine Dependency zum AC unausweichlich ist (weil du beispielsweise eine BeanPostProcessor implementieren willst und dafür weitere Infos aus dem AC benötigst) ist ApplicationContextAware das Interface deiner Wahl.
Danke für diesen Hinweis, aber ich glaube in meinem Fall ist das nichts.
Das ist jetzt eher grundsätzlich, spiegelt aber auch grundsätzlich die Arbeit mit Spring wieder. Man wird "genötigt" sich über Dependencies Gedanken zu machen und kommt auf die Art und Weise zu besserem und testbareren Code.
Ja, da möchte ich auch hin
Das sollte dir jetzt schon ein paar Anhaltspunkte für eine Entscheidung geben. Was hast du denn genau vor?
Gut, dann werde ich mal eben eklären, vor welchem Problem ich stehe:
Ausgangssituation:
In meinem Projekt gibt es eine große Anzahl an Eingabemasken. Diese möchte ich nicht von Hand erstellen (den Swing Code schreiben), sondern mit einem GUI-Builder-Tool (z.B. Jogloo Eclipse Plugin der JFormDesigner, was auch immer...) erstellen. Erstmal aus Geschwindigkeitsgründen (man ist mit dem Tool immer schneller, als das ganze Layout Management von Hand zu machen), und dann auch noch, weil sogar jemand, der sich nicht mit Java auskennt, das Tool benutzen kann, um die Masken zu bauen (quasi "Outsourcing"

.
Wie auch immer, der GUI Code wird generiert und ich habe eine Art von UIAdapter, der über Reflection auf die Komponenten zugreifen kann. Ein wie ich finde schöner ansatz, um Layout und Code voneinander zu trennen (noch stärker als das "normale" MVC).
Nun ist es so, dass ich auch noch neue Oberflächen-Komponenten habe - eigene Klassen, die ihren Client-Bereich selbst zeichnen. Darunter zeichnen sie einige Bilder, die als png Dateien vorliegen. Diese Bilder - Resourcen - können durch eine Klasse "ResourceManager" geladen werden. Diese Komponenten sind also Abhängig von dem ResourceLoader. Da haben wir ja schon einen Anwendungsfall für Spring - denn es könnte den Komponentenklassen den ResourceManagern injizieren. Ich hoffe ich habe Spring bis hierhin verstanden (bzw. allg. "Dep. Injection"?)
Das Problem:
Jetzt kommen wir zum Kern der Sache: möchte ich eine Maske mit dem Tool editieren, so instanziert das Tool meine Klasse (meist ein einfaches JPanel) sowie alle darin enthaltenen Komponenten (JButton, JTextField, was auch immer) sowie eben auch meine eigene Komponente (die den ResourceManager braucht).
Theoretisch müsste das Tool vorher einen ApplicationContext erzeugen, Spring erstellt also die GUI-Komponenten, injiziert ihnen den ResourceManager (der zuvor auch von Spring instanziert wurde) und so können die Komponenten auch Zugriff auf die Bilder-Resourcen erhalten.
Aber das wird so nichts - denn der Editor hat keine Ahnung von einem AppContext, er erzeugt die GUI-Komponenten selbst und ich möchte eigentlich keinen Einfluss auf den generierten Code haben. Deshalb dachte ich mir, dass jede meiner eigenen GUI-Komponenten sich den ApplicationContext holt, damit sie dann schließlich Zugriff auf den ResourceManager hat.
Wenn das Programm selbst abläuft, sodass ich vorher einen ApplicationContext erstellen kann, meine GUI-Komponenten Beans sind, diese eine Abhängigkeit vom ResourceManager haben, dann wäre das alles kein Problem (denke ich). Aber in dieser Situation weiß ich einfach keine andere Lösung, als dass ich einen globalen Zugriff auf den ApplicationContext aus einer GUI-Komponenten heraus habe, um darüber dann auf meinen ResourceManager zugreifen zu können.
So, nun ist die Erklärung doch schon länger geworden - ich hoffe sehr, dass alles verständlich ist. Vielleicht hast Du eine Idee dazu? Kann man es mit Spring-Boardmitteln lösen? Oder brauche ich doch nen Singleton, auf den ich Zugriff aus der GUI-Komponente nehme?
Vielen Dank für Deine weitere Hilfe!