← Назад к вопросам
Может ли Scope Request существовать в GenericApplicationContext?
1.8 Middle🔥 161 комментариев
#Другое
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Request Scope в GenericApplicationContext
Краткий ответ: НЕТ, Request Scope не может существовать в GenericApplicationContext по умолчанию.
Это один из ключевых различий между типами Application Context в Spring. Давайте разберемся подробно.
Разница между Application Context
1. WebApplicationContext (Веб-приложения)
// WebApplicationContext ПОДДЕРЖИВАЕТ Request Scope
@Configuration
public class WebConfig {
@Bean
@Scope("request") // Работает отлично
public UserService userService() {
return new UserService();
}
}
// Использование в контроллере
@RestController
public class UserController {
@Autowired
private UserService userService; // Request-scoped bean
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
// userService — новый экземпляр для каждого request
return userService.getUser(id);
}
}
Как это работает:
- WebApplicationContext имеет доступ к ServletRequest
- Для каждого HTTP запроса создается новый request scope
- Bean уничтожается в конце обработки запроса
2. GenericApplicationContext (обычные приложения)
// GenericApplicationContext НЕ ПОДДЕРЖИВАЕТ Request Scope
public class MyApplication {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
// Регистрируем конфигурацию
context.registerBean(MyService.class);
context.refresh();
// Это РАБОТАЕТ (Singleton Scope)
MyService service1 = context.getBean(MyService.class);
MyService service2 = context.getBean(MyService.class);
System.out.println(service1 == service2); // true (один экземпляр)
// Это НЕ РАБОТАЕТ (Request Scope отсутствует)
// context.registerBean(UserService.class, "request"); // Ошибка!
}
}
Почему Request Scope не работает в GenericApplicationContext?
// Request Scope требует WebApplicationContext
public interface Scope {
Object get(String name, ObjectFactory<?> objectFactory);
void registerDestructionCallback(String name, Runnable callback);
Object remove(String name);
String getConversationId();
}
// Request Scope имплементирует этот интерфейс
public class RequestScope implements Scope {
// Использует ThreadLocal для хранения request scope beans
private static final ThreadLocal<Map<String, Object>> requestScope =
new ThreadLocal<>();
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = requestScope.get();
// Требует наличия ServletRequest в текущем потоке
if (scope == null) {
throw new IllegalStateException(
"No thread-bound request found");
}
// ...
}
}
Основные проблемы:
- GenericApplicationContext не регистрирует Request Scope автоматически
- Нет ServletRequest в контексте обычного приложения
- Request Scope требует HTTP контекста, которого нет в консольных/батник приложениях
Что нужно использовать вместо GenericApplicationContext для веб-приложений
1. Spring Boot (рекомендуется)
// application.properties
spring.application.name=my-app
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
// Автоматически создает WebApplicationContext
// Request Scope работает "из коробки"
}
}
@Configuration
public class BeanConfig {
@Bean
@Scope("request") // Работает!
public UserContext userContext() {
return new UserContext();
}
}
2. AnnotationConfigWebApplicationContext
public class WebApplicationStartup {
public static void main(String[] args) {
// Для веб-приложений БЕЗ Spring Boot
AnnotationConfigWebApplicationContext context =
new AnnotationConfigWebApplicationContext();
context.register(WebConfig.class);
context.refresh();
// Теперь Request Scope работает!
}
}
@Configuration
public class WebConfig {
@Bean
@Scope("request") // Работает в WebApplicationContext
public UserContext userContext() {
return new UserContext();
}
}
3. ClassPathXmlApplicationContext (в web.xml)
<!-- web.xml -->
<web-app>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/application-context.xml</param-value>
</context-param>
</web-app>
<!-- application-context.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Request Scope работает в web контексте -->
<bean id="userContext" class="com.example.UserContext" scope="request">
<aop:scoped-proxy/>
</bean>
</beans>
Можно ли добавить Request Scope в GenericApplicationContext?
// ТЕХНИЧЕСКИ можно, но это плохая идея
public class GenericContextWithRequestScope {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
// Регистрируем Request Scope вручную
context.getBeanFactory().registerScope("request",
new SimpleMapScope());
// Но это не будет работать как надо, потому что:
// 1. Нет HTTP запросов
// 2. Нет ServletRequest в потоке
// 3. Scope не очищается автоматически
}
}
// SimpleMapScope — простая реализация (из примеров)
public class SimpleMapScope implements Scope {
private final Map<String, Object> scope = new HashMap<>();
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
return scope.computeIfAbsent(name, k -> objectFactory.getObject());
}
@Override
public String getConversationId() {
return null;
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
// Ничего не делает
}
@Override
public Object remove(String name) {
return scope.remove(name);
}
}
Практические примеры
Что работает в GenericApplicationContext
public class GenericContextExample {
public static void main(String[] args) {
GenericApplicationContext context = new GenericApplicationContext();
// ✅ РАБОТАЕТ: Singleton Scope (по умолчанию)
context.registerBean("singletonService", SingletonService.class);
// ✅ РАБОТАЕТ: Prototype Scope
context.registerBean(
"prototypeService",
PrototypeService.class,
bd -> bd.setScope("prototype")
);
// ✅ РАБОТАЕТ: Custom Scope (если зарегистрирован)
context.getBeanFactory().registerScope("custom", new CustomScope());
context.registerBean(
"customService",
CustomService.class,
bd -> bd.setScope("custom")
);
// ❌ НЕ РАБОТАЕТ: Request Scope
// context.registerBean(
// "requestService",
// RequestService.class,
// bd -> bd.setScope("request") // Будет ошибка!
// );
context.refresh();
}
}
Что работает в WebApplicationContext
@Configuration
public class WebContextExample {
// ✅ Singleton (по умолчанию)
@Bean
public SingletonService singletonService() {
return new SingletonService();
}
// ✅ Prototype
@Bean
@Scope("prototype")
public PrototypeService prototypeService() {
return new PrototypeService();
}
// ✅ Session
@Bean
@Scope("session")
public SessionUser sessionUser() {
return new SessionUser();
}
// ✅ REQUEST (работает ТОЛЬКО в WebApplicationContext)
@Bean
@Scope("request")
public RequestUser requestUser() {
return new RequestUser();
}
// ✅ WebSocket Scope
@Bean
@Scope("websocket")
public WebSocketMessage wsMessage() {
return new WebSocketMessage();
}
}
Таблица сравнения
| Scope | GenericApplicationContext | WebApplicationContext | AnnotationConfigApplicationContext | AnnotationConfigWebApplicationContext |
|---|---|---|---|---|
| Singleton | ✅ | ✅ | ✅ | ✅ |
| Prototype | ✅ | ✅ | ✅ | ✅ |
| Request | ❌ | ✅ | ❌ | ✅ |
| Session | ❌ | ✅ | ❌ | ✅ |
| WebSocket | ❌ | ✅ | ❌ | ✅ |
| Custom | ✅ | ✅ | ✅ | ✅ |
Заключение
Ответ: НЕТ, Request Scope НЕ может существовать в GenericApplicationContext.
Причины:
- GenericApplicationContext не регистрирует Request Scope
- Request Scope требует ServletRequest в потоке
- GenericApplicationContext используется для не-веб приложений
Решение:
- Используй WebApplicationContext или его подклассы для веб-приложений
- Для Spring Boot это происходит автоматически
- Для обычных веб-приложений используй AnnotationConfigWebApplicationContext
- Если нужен Request Scope, нужен веб контекст