Ответ
Scope зависимости в Spring — это область видимости бина, который внедряется как зависимость. Поведение при инъекции зависит от соотношения Scope'ов зависимого бина (клиента) и внедряемого бина (зависимости).
Основные сценарии и правила:
- Singleton, зависящий от Singleton: Стандартный случай. Один экземпляр зависимости внедряется в один экземпляр клиента.
- Singleton, зависящий от Prototype: Проблема! Prototype-бин будет внедрён в singleton только один раз при его создании, и singleton будет всегда использовать этот единственный экземпляр, теряя смысл prototype.
Решение проблемы Singleton -> Prototype:
а) Использование ObjectProvider (или Provider в javax.inject):
@Component
public class SingletonClient {
@Autowired
private ObjectProvider<PrototypeDependency> dependencyProvider;
public void doWork() {
PrototypeDependency dependency = dependencyProvider.getObject(); // Новый экземпляр при каждом вызове!
dependency.process();
}
}
б) Lookup Method Injection (менее распространён):
@Component
public abstract class SingletonClient {
public void doWork() {
PrototypeDependency dependency = getPrototypeDependency(); // Spring переопределит этот метод
dependency.process();
}
@Lookup
protected abstract PrototypeDependency getPrototypeDependency();
}
в) Использование прокси (@Scope(proxyMode=...)):
@Component
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class PrototypeDependency { /* ... */ }
@Component
public class SingletonClient {
@Autowired
private PrototypeDependency dependency; // Внедряется прокси
// Каждый вызов метода dependency.someMethod() будет идти через прокси,
// который может создать новый экземпляр (поведение зависит от реализации).
}
- Prototype, зависящий от Prototype: Каждый новый экземпляр клиента получит новый экземпляр зависимости (или тот же, если инъекция происходит в одном месте контекста).
- Request/Session Scope в Singleton: Для корректной работы singleton-бина (например, сервиса) с request/session-бинами (например, моделью пользователя) зависимость также должна быть проксирована (
proxyMode = ScopedProxyMode.TARGET_CLASS).
Вывод: При проектировании зависимостей необходимо учитывать их Scope, чтобы избежать неожиданного поведения, особенно при комбинации долгоживущих (singleton) и короткоживущих (prototype, request) бинов.