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

Какой Scope нужно добавить контроллеру для управления ходом запросов в контроллер?

2.2 Middle🔥 201 комментариев
#Основы Java

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

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

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

Scope REQUEST для управления ходом запросов в контроллер

Вопрос касается одного из ключевых аспектов Spring Framework — управления жизненным циклом bean'ов в контексте HTTP-запроса. Чтобы контроллер мог эффективно управлять ходом запросов, необходимо использовать REQUEST scope (или точнее, beans'ы с REQUEST scope в зависимостях контроллера).

Что такое REQUEST Scope

REQUEST scope — это область видимости bean'а, которая существует на протяжении одного HTTP-запроса. Каждый новый запрос получает новый экземпляр bean'а, что обеспечивает:

  • Изоляцию данных между запросами
  • Отсутствие race conditions в многопоточной среде
  • Автоматическую очистку после завершения запроса

Как использовать REQUEST Scope в контроллере

// Сервис с REQUEST scope
@Component
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class RequestTracker {
    private String requestId;
    private LocalDateTime startTime;
    private Map<String, Object> requestAttributes = new HashMap<>();
    
    public void initRequest() {
        this.requestId = UUID.randomUUID().toString();
        this.startTime = LocalDateTime.now();
    }
    
    public void setAttribute(String key, Object value) {
        requestAttributes.put(key, value);
    }
    
    public String getRequestId() {
        return requestId;
    }
}

// Контроллер использует REQUEST-scoped сервис
@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;
    private final RequestTracker requestTracker;  // REQUEST scope
    
    @Autowired
    public UserController(UserService userService, RequestTracker requestTracker) {
        this.userService = userService;
        this.requestTracker = requestTracker;
    }
    
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        requestTracker.initRequest();
        logger.info("Request ID: {}", requestTracker.getRequestId());
        
        User user = userService.findById(id);
        requestTracker.setAttribute("userFound", user != null);
        
        return ResponseEntity.ok(new UserDTO(user));
    }
}

Альтернативные Scope'ы

// SESSION scope — существует на протяжении сессии пользователя
@Component
@Scope(WebApplicationContext.SCOPE_SESSION)
public class UserSession {
    private User currentUser;
}

// APPLICATION scope (SINGLETON) — один экземпляр на всё приложение
@Component
@Scope(WebApplicationContext.SCOPE_APPLICATION)
public class AppConfig {
    private ApplicationProperties properties;
}

// PROTOTYPE — новый экземпляр каждый раз при инъекции
@Component
@Scope(WebApplicationContext.SCOPE_PROTOTYPE)
public class RequestProcessor {
}

Практический пример с управлением ходом запроса

@Component
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class RequestContextManager {
    private String correlationId;
    private List<String> executionSteps = new ArrayList<>();
    private boolean isProcessing = false;
    
    public void startProcessing() {
        this.correlationId = UUID.randomUUID().toString();
        this.isProcessing = true;
        executionSteps.add("Processing started at " + LocalDateTime.now());
    }
    
    public void addExecutionStep(String step) {
        executionSteps.add(step);
    }
    
    public void completeProcessing() {
        isProcessing = false;
        executionSteps.add("Processing completed at " + LocalDateTime.now());
    }
    
    public List<String> getExecutionLog() {
        return new ArrayList<>(executionSteps);
    }
}

@RestController
@RequestMapping("/api/orders")
public class OrderController {
    private final OrderService orderService;
    private final RequestContextManager requestManager;
    
    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@RequestBody CreateOrderRequest request) {
        requestManager.startProcessing();
        
        try {
            requestManager.addExecutionStep("Validating order...");
            Order order = orderService.validateAndCreate(request);
            
            requestManager.addExecutionStep("Order created with ID: " + order.getId());
            requestManager.completeProcessing();
            
            return ResponseEntity.status(HttpStatus.CREATED).body(new OrderDTO(order));
        } catch (Exception e) {
            requestManager.addExecutionStep("Error: " + e.getMessage());
            throw e;
        }
    }
}

Важные моменты

  • Request scope требует web-контекста: работает только в Spring MVC или WebFlux приложениях
  • Не используй request-scoped beans в Singleton'ах: это приводит к AOP proxy проблемам
  • Потокобезопасность: REQUEST scope автоматически обеспечивает безопасность, т.к. каждый поток имеет свой bean

Использование REQUEST scope позволяет контроллерам эффективно управлять состоянием на протяжении жизненного цикла одного HTTP-запроса.