@ Lookup Annotation im Frühjahr

1. Einleitung

In diesem kurzen Tutorial werfen wir einen Blick auf die Unterstützung der Abhängigkeitsinjektion auf Methodenebene auf Spring-Ebene über die Annotation @Lookup .

2. Warum @Lookup ?

Eine mit @Lookup kommentierte Methode weist Spring an, eine Instanz des Rückgabetyps der Methode zurückzugeben, wenn wir sie aufrufen.

Im Wesentlichen überschreibt Spring unsere mit Anmerkungen versehene Methode und verwendet den Rückgabetyp und die Parameter unserer Methode als Argumente für BeanFactory # getBean.

@Lookup ist nützlich für:

  • Injizieren einer Bean mit Prototyp-Gültigkeitsbereich in eine Singleton-Bean (ähnlich wie Provider )
  • Abhängigkeiten prozedural einfügen

Beachten Sie auch, dass @Lookup das Java-Äquivalent der XML-Element- Lookup-Methode ist .

3. Verwenden von @Lookup

3.1. Injizieren einer Bean mit Prototyp-Umfang in eine Singleton-Bohne

Wenn wir uns zufällig für einen Spring Bean-Prototyp entscheiden, stehen wir fast sofort vor dem Problem, wie unsere Singleton Spring Beans auf diese Spring Bean-Prototypen zugreifen können.

Jetzt ist Provider sicherlich eine Möglichkeit, obwohl @Lookup in mancher Hinsicht vielseitiger ist.

Lassen Sie uns zunächst eine Prototyp-Bean erstellen, die wir später in eine Singleton-Bean injizieren werden:

@Component @Scope("prototype") public class SchoolNotification { // ... prototype-scoped state }

Und wenn wir eine Singleton-Bean erstellen, die @Lookup verwendet :

@Component public class StudentServices { // ... member variables, etc. @Lookup public SchoolNotification getNotification() { return null; } // ... getters and setters }

Mit @Lookup können wir eine Instanz von SchoolNotification über unsere Singleton-Bean abrufen :

@Test public void whenLookupMethodCalled_thenNewInstanceReturned() { // ... initialize context StudentServices first = this.context.getBean(StudentServices.class); StudentServices second = this.context.getBean(StudentServices.class); assertEquals(first, second); assertNotEquals(first.getNotification(), second.getNotification()); }

Beachten Sie, dass in StudentServices wir die linke getNotification Methode als Stummel.

Dies liegt daran, dass Spring die Methode mit einem Aufruf von beanFactory.getBean (StudentNotification.class) überschreibt , sodass wir sie leer lassen können.

3.2. Abhängigkeiten prozedural injizieren

Noch mächtiger ist jedoch, dass @Lookup es uns ermöglicht, eine Abhängigkeit prozedural einzufügen , was wir mit Provider nicht tun können .

Lassen Sie uns StudentNotification mit einem Status erweitern:

@Component @Scope("prototype") public class SchoolNotification { @Autowired Grader grader; private String name; private Collection marks; public SchoolNotification(String name) { // ... set fields } // ... getters and setters public String addMark(Integer mark) { this.marks.add(mark); return this.grader.grade(this.marks); } }

Jetzt hängt es von einem Frühlingskontext und einem zusätzlichen Kontext ab, den wir prozedural bereitstellen werden.

Wir können dann eine Methode hinzufügen StudentServices die Schülerdaten nimmt und hält es:

public abstract class StudentServices { private Map notes = new HashMap(); @Lookup protected abstract SchoolNotification getNotification(String name); public String appendMark(String name, Integer mark) { SchoolNotification notification = notes.computeIfAbsent(name, exists -> getNotification(name))); return notification.addMark(mark); } } 

Zur Laufzeit implementiert Spring die Methode auf die gleiche Weise mit ein paar zusätzlichen Tricks.

Beachten Sie zunächst, dass es einen komplexen Konstruktor aufrufen und andere Spring Beans injizieren kann, sodass wir SchoolNotification ein bisschen mehr wie eine Spring-fähige Methode behandeln können.

Dazu wird getSchoolNotification mit einem Aufruf von beanFactory.getBean (SchoolNotification.class, name) implementiert .

Zweitens können wir manchmal die mit @ Lookup annotierte Methode abstrakt machen, wie im obigen Beispiel.

Die Verwendung von abstract sieht ein bisschen besser aus als ein Stub, aber wir können es nur verwenden, wenn wir die umgebende Bean nicht mit Komponenten scannen oder @Bean verwalten :

@Test public void whenAbstractGetterMethodInjects_thenNewInstanceReturned() { // ... initialize context StudentServices services = context.getBean(StudentServices.class); assertEquals("PASS", services.appendMark("Alex", 89)); assertEquals("FAIL", services.appendMark("Bethany", 78)); assertEquals("PASS", services.appendMark("Claire", 96)); }

Mit dieser Einrichtung können wir Frühling Abhängigkeiten sowie Verfahren Abhängigkeiten hinzuzufügen SchoolNotification .

4. Einschränkungen

Trotz der Vielseitigkeit von @Lookup gibt es einige bemerkenswerte Einschränkungen:

  • @ Lookup- annotierte Methoden wie getNotification müssen konkret sein, wenn die umgebende Klasse wie Student von Komponenten gescannt wird. Dies liegt daran, dass beim Scannen von Komponenten abstrakte Beans übersprungen werden.
  • Mit @ Lookup kommentierte Methoden funktionieren überhaupt nicht, wenn die umgebende Klasse mit @Bean verwaltet wird.

Wenn wir unter diesen Umständen eine Prototyp-Bean in einen Singleton injizieren müssen, können wir uns alternativ an Provider wenden.

5. Schlussfolgerung

In diesem kurzen Artikel haben wir gelernt, wie und wann die @ Lookup- Annotation von Spring verwendet wird , einschließlich der Verwendung zum Injizieren von Prototyp-Beans in Singleton-Beans und zum prozeduralen Injizieren von Abhängigkeiten.

Der gesamte Code, der für dieses Tutorial verwendet wird, befindet sich auf Github.