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 .