Вопрос проверяет понимание аннотации @Lookup в Spring, которая используется для внедрения прототипных бинов в синглтон-бины, чтобы избежать проблем с состоянием.
В Spring Framework аннотация @Lookup решает классическую проблему внедрения зависимостей: как синглтон-бин (который создаётся один раз) может каждый раз получать новый экземпляр прототип-бина (который создаётся при каждом запросе). Без @Lookup, если прототип-бин внедряется в синглтон через конструктор или поле, он будет инжектирован только один раз при создании синглтона, и синглтон будет всегда использовать один и тот же экземпляр, теряя преимущество прототипа.
Spring использует механизм CGLIB для создания подкласса того класса, где объявлен метод с @Lookup. При вызове этого метода Spring перехватывает его и возвращает новый бин из контекста приложения. Метод может быть абстрактным или иметь пустую реализацию — Spring предоставит реализацию.
Предположим, у нас есть прототип-бин PrototypeService, который содержит состояние (например, идентификатор сессии), и синглтон SingletonService, который должен использовать новый экземпляр PrototypeService при каждом вызове.
// Прототип-бин с областью видимости prototype
@Component
@Scope("prototype")
public class PrototypeService {
private String sessionId;
public PrototypeService() {
this.sessionId = UUID.randomUUID().toString();
}
public String getSessionId() {
return sessionId;
}
}
// Синглтон-бин, использующий @Lookup
@Component
public class SingletonService {
// Аннотированный метод: Spring обеспечит получение нового PrototypeService
@Lookup
public PrototypeService getPrototypeService() {
return null; // Реализация будет предоставлена Spring
}
public void process() {
PrototypeService ps = getPrototypeService();
System.out.println("Используется PrototypeService с ID: " + ps.getSessionId());
// При следующем вызове getPrototypeService() будет возвращён новый экземпляр
}
}Вывод: Используйте @Lookup в Spring, когда синглтон-компонент должен каждый раз работать с новым экземпляром прототип-бина, особенно если этот прототип содержит изменяемое состояние, которое не должно разделяться между вызовами. Это чистое решение, которое сохраняет преимущества Spring DI без ручного доступа к ApplicationContext.