← Назад к вопросам

Какие знаешь области видимости в Spring?

2.0 Middle🔥 121 комментариев
#Spring Boot и Spring Data#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Области видимости (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 объектыНе требуется
RequestHTTP запросДанные запросаМожет быть нарушена
SessionСессия пользователяПользовательские данныеОсторожно
ApplicationServletContextГлобальные метрикиОбязательна
WebSocketWebSocket соединение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 в многопоточной среде.

Какие знаешь области видимости в Spring? | PrepBro