Какие знаешь области видимости в Spring?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Области видимости (Scopes) в Spring
В Spring Framework scope определяет жизненный цикл и область видимости бина в контексте приложения. Существует несколько предопределённых скопов, каждый из которых подходит для разных сценариев.
1. Singleton (По умолчанию)
Создаётся один экземпляр бина на всё приложение и переиспользуется повсюду. Это самый экономный вариант по памяти.
@Component
// или явно
@Scope("singleton")
public class DatabaseConnection {
private String url;
public DatabaseConnection() {
System.out.println("DatabaseConnection создана");
}
}
@Configuration
public class AppConfig {
@Bean
@Scope("singleton")
public UserService userService() {
return new UserService();
}
}
Характеристики:
- Один объект на контекст
- Потокобезопасность обязательна
- Максимальная производительность
- Подходит для сервисов, конфигураций, DAO
2. Prototype
Создаётся новый экземпляр при каждом запросе бина. Полностью изолированные объекты.
@Component
@Scope("prototype")
public class RequestContext {
private String sessionId;
public RequestContext() {
System.out.println("Новый RequestContext создан");
}
}
Характеристики:
- Новый объект каждый раз
- Без кеширования
- Больше нагрузка на память
- Подходит для stateful объектов
@Service
public class UserService {
@Autowired
private ApplicationContext context;
public void processRequest() {
// Каждый раз будет новый экземпляр
RequestContext ctx1 = context.getBean(RequestContext.class);
RequestContext ctx2 = context.getBean(RequestContext.class);
System.out.println(ctx1 == ctx2); // false
}
}
3. Request (Web-приложения)
Создаётся один экземпляр на HTTP-запрос. Доступен только в контексте веб-приложения.
@Component
@Scope("request")
public class HttpRequest {
private String userId;
private long createdAt = System.currentTimeMillis();
public String getUserId() {
return userId;
}
}
Использование в контроллере:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private HttpRequest httpRequest; // Инжектируется для каждого запроса
@GetMapping("/{id}")
public User getUser(@PathVariable String id) {
String userId = httpRequest.getUserId();
return new User(id, userId);
}
}
4. Session (Web-приложения)
Создаётся один экземпляр на HTTP-сессию. Живёт столько же, сколько сессия пользователя.
@Component
@Scope("session")
public class UserSession {
private String username;
private List<String> preferences = new ArrayList<>();
public void addPreference(String pref) {
preferences.add(pref);
}
}
Характеристики:
- Один объект на сессию
- Сохраняет состояние между запросами
- Завершается при закрытии сессии
- Требует сериализации для распределённых сессий
5. Application (Web-приложения)
Создаётся один экземпляр на ServletContext. Общий для всего приложения в контексте веб-сервера.
@Component
@Scope("application")
public class ApplicationMetrics {
private int totalRequests = 0;
public synchronized void incrementRequests() {
totalRequests++;
}
}
6. WebSocket (Spring 4.0+)
Создаётся один экземпляр на WebSocket соединение. Для real-time приложений.
@Component
@Scope("websocket")
public class WebSocketSession {
private String connectionId;
}
Сравнительная таблица
| Scope | Жизненный цикл | Использование | Потокобезопасность |
|---|---|---|---|
| Singleton | Контекст приложения | Сервисы, DAO | Обязательна |
| Prototype | На запрос | Stateful объекты | Не требуется |
| Request | HTTP запрос | Данные запроса | Может быть нарушена |
| Session | Сессия пользователя | Пользовательские данные | Осторожно |
| Application | ServletContext | Глобальные метрики | Обязательна |
| WebSocket | WebSocket соединение | Real-time данные | Не требуется |
Практический пример: Комбинирование скопов
@Service
public class UserService { // Singleton
@Autowired
private ApplicationContext context;
public void handleRequest(String userId) {
// Получаем request-scoped объект
HttpRequest httpRequest = context.getBean(HttpRequest.class);
// Получаем session-scoped объект
UserSession session = context.getBean(UserSession.class);
session.addPreference(userId);
}
}
Проблемы и решения
Инжекция request/session бина в singleton:
// ❌ Неправильно
@Service
public class MyService {
@Autowired
private HttpRequest httpRequest; // Разово инжектируется!
}
// ✅ Правильно - используй ObjectProvider
@Service
public class MyService {
@Autowired
private ObjectProvider<HttpRequest> httpRequestProvider;
public void process() {
HttpRequest httpRequest = httpRequestProvider.getIfAvailable();
}
}
// ✅ Или прокси-режим
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HttpRequest httpRequest() {
return new HttpRequest();
}
Выбор правильного scope — ключ к оптимизации приложения, управлению памятью и избежанию race conditions в многопоточной среде.