Ich habe eine Java EE + Spring-App, die Annotationen gegenüber der XML-Konfiguration bevorzugt. Die Beans haben immer einen Prototypbereich.
Ich habe jetzt in meiner App Geschäftsregeln, die von dem Land abhängen, aus dem die Benutzeranfrage stammt. Also hätte ich so etwas (beachte, dass dieses Beispiel stark vereinfacht wurde):
%Vor%Ich suchte nach einer Möglichkeit, den automatischen Verdrahtungsmechanismus automatisch die richtige Bohne (in diesem Beispiel entweder USA oder Kanada) basierend auf dem Land der aktuellen Anfrage zu injizieren. Das Land würde in einer ThreadLocal-Variablen gespeichert und bei jeder Anfrage geändert. Es würde auch eine globale Klasse geben, für alle Länder, die keine eigenen Regeln haben.
Ich würde mir vorstellen, dass ich die Art und Weise anpassen müsste, in der Spring entscheidet, wie die Objekte erstellt werden, die injiziert werden. Die einzige Möglichkeit, dies zu tun, war die Verwendung von FactoryBean, aber das war nicht ganz das, was ich mir erhofft hatte (nicht generisch genug). Ich hatte gehofft, so etwas zu tun:
Bin ich auf dem richtigen Weg? Irgendwelche Ideen für mich dazu?
Danke.
Erstellen Sie Ihre eigene Annotation, die zur Verzierung von Instanzvariablen oder Setter-Methoden verwendet wird, und anschließend einen Postprozessor, der die Annotation verarbeitet und einen generischen Proxy einfügt, der die korrekte Implementierung zur Laufzeit auflöst und den Aufruf an ihn delegiert.
%Vor% Hier ist der Algorithmus für die Methode postProcessBeforeInitialization(bean, beanName)
in Ihrem Bean-Postprozessor:
InjectionMetadata
verwenden. Sie können nach Beispielen suchen, wie es funktioniert, indem Sie Referenzen auf diese Klasse im Springcode suchen. Hier ist der InvocationHandler für den Proxy, der zum Erstellen lokalisierter Ressourcen verwendet wird.
%Vor%Sie müssen möglicherweise mehr Steuerelemente für den Bean-Typ festlegen oder den angeforderten Bean-Typ im InvocationHandler hinzufügen.
Als nächstes müssen Sie Implementierungen einer gegebenen Schnittstelle, die lokal abhängig sind, automatisch erkennen und sie mit dem Qualifikationsmerkmal registrieren, das dem Gebietsschema entspricht. Sie können zu diesem Zweck ein BeanDefinitionRegistryPostProcessor
oder BeanFactoryPostProcessor
implementieren, um der Registrierung ein neues BeanDefinition
s hinzuzufügen, mit einem geeigneten Qualifikationsmerkmal, eines für jede Implementierung von länderspezifischen Schnittstellen. Sie können das Gebietsschema einer Implementierung anhand von Namenskonventionen erraten: Wenn eine länderspezifische Schnittstelle TransactionRules genannt wird, können Implementierungen im selben Paket den Namen Transac- tionRules_ISOCODE tragen.
Wenn Sie sich eine solche Namenskonvention nicht leisten können, müssen Sie eine Art Klassenpfad-Überprüfung durchführen + eine Möglichkeit, das Gebietsschema einer bestimmten Implementierung zu erraten (möglicherweise eine Anmerkung zu den Implementierungsklassen). Classpath-Scanning ist möglich, aber ziemlich komplex und langsam, also versuchen Sie es zu vermeiden.
Hier ist eine Zusammenfassung dessen, was passiert:
Nicht wirklich trivial, aber es funktioniert. So wird @PersistenceContext von Spring verarbeitet, mit Ausnahme der Implementierungssuche, die ein zusätzliches Feature Ihres Anwendungsfalls darstellt.
Sie können eine Konfigurationsklasse angeben, die basierend auf dem ThreadLocal-Wert die richtige Bean zurückgibt. Dies setzt voraus, dass Sie Spring 3 verwenden. Ich habe einen kleinen Test durchgeführt, um sicherzustellen, dass die Provider-Methode bei jeder Anfrage aufgerufen wurde. Hier ist was ich getan habe.
%Vor%Und referenzierte den Wert in meinem Controller wie folgt.
%Vor%In Ihrer Implementierung des Providers können Sie das ThreadLocal für das Gebietsschema überprüfen und das korrekte TransactionRules-Objekt oder etwas ähnliches zurückgeben. Das ScopedProxy-Zeug ist, weil ich in einen Controller injiziert habe, der Singleton-Bereich ist, während der Wert Request-Bereich ist.