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 Collectionmarks; 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 Mapnotes = 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 .