Рубрики
Без рубрики

Аннотация @Lookup весной

Узнайте, как эффективно использовать аннотацию @Lookup в Spring для процедурного внедрения.

Автор оригинала: baeldung.

1. введение

В этом кратком руководстве мы рассмотрим поддержку внедрения зависимостей на уровне методов Spring с помощью аннотации @Lookup .

2. Почему @Lookup?

Метод, аннотированный @Поиск говорит Spring возвращать экземпляр возвращаемого типа метода при его вызове.

По сути, Spring переопределит наш аннотированный метод и будет использовать возвращаемый тип и параметры нашего метода в качестве аргументов для BeanFactory#getBean.

@Lookup полезен для:

  • Инъекция компонента с областью действия прототипа в одноэлементный компонент (аналогично Provider )
  • Процедурное введение зависимостей

Обратите также внимание, что @Lookup является Java-эквивалентом XML-элемента lookup-method .

3. Использование @Lookup

3.1. Инъекция Компонента с областью действия прототипа В одноэлементный Компонент

Если мы решим создать прототип весеннего боба, то почти сразу столкнемся с проблемой, как наши одноэлементные весенние бобы получат доступ к этим прототипным весенним бобам?

Теперь, Provider , безусловно, один из способов, через @Lookup более универсален в некоторых отношениях.

Во-первых, давайте создадим прототип боба, который мы позже введем в одноэлементный боб:

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

И если мы создадим одноэлементный компонент, который использует @Lookup :

@Component
public class StudentServices {

    // ... member variables, etc.

    @Lookup
    public SchoolNotification getNotification() {
        return null;
    }

    // ... getters and setters
}

Использование @Lookup , мы можем получить экземпляр Школьного уведомления через наш одноэлементный компонент:

@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()); 
}

Обратите внимание , что в Student Services мы оставили метод get Notification в качестве заглушки.

Это связано с тем, что Spring переопределяет метод вызовом BeanFactory.getBean(StudentNotification.class) , так что мы можем оставить его пустым.

3.2. Процедурное Введение Зависимостей

Еще более мощным, однако, является то, что @Lookup позволяет нам процедурно вводить зависимость, что мы не можем сделать с Provider .

Давайте улучшим Уведомление студента с некоторым состоянием:

@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);
    }
}

Теперь это зависит от некоторого весеннего контекста, а также от дополнительного контекста, который мы предоставим процедурно.

Затем мы можем добавить метод в Student Services , который принимает данные о студентах и сохраняет их:

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);
    }
}

Во время выполнения Spring будет реализовывать метод таким же образом, с несколькими дополнительными трюками.

Во-первых, обратите внимание, что он может вызывать сложный конструктор, а также вводить другие компоненты Spring, что позволяет нам рассматривать SchoolNotification немного больше как метод с поддержкой Spring.

Он делает это, реализуя get School Notification с вызовом BeanFactory.getBean(SchoolNotification.class, имя) .

Во – вторых, иногда мы можем сделать @Lookup – аннотированный метод абстрактным, как в приведенном выше примере.

Использование abstract выглядит немного приятнее, чем заглушка, но мы можем использовать его только тогда, когда мы не | сканируем компоненты или @Bean -управляем окружающим бобом:

@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));
}

С помощью этой настройки мы можем добавить зависимости Spring, а также зависимости методов в School Notification .

4. Ограничения

Несмотря на универсальность @Lookup , есть несколько заметных ограничений:

  • @@Lookup -аннотированные методы, такие как get Notification, должны быть конкретными, когда окружающий класс, например Student, сканируется компонентом. Это связано с тем, что сканирование компонентов пропускает абстрактные компоненты.
  • @Lookup- аннотированные методы вообще не будут работать, когда окружающий класс управляется @Bean .

В этих обстоятельствах, если нам нужно внедрить компонент-прототип в синглтон, мы можем обратиться к Provider в качестве альтернативы.

5. Заключение

В этой краткой статье мы узнали, как и когда использовать аннотацию Spring @Lookup , в том числе как использовать ее для внедрения компонентов с областью прототипа в одноэлементные компоненты и как использовать ее для процедурного внедрения зависимостей.

Весь код, используемый для этого урока, можно найти на Github .