SoFunction
Updated on 2025-04-10

Spring Boot Regularly use HttpServletRequest method in asynchronous threads

Preface

In modern web development, it has become a common practice to use asynchronous threads to handle long-running tasks (such as file export, large-scale data processing, etc.).

Spring provides a variety of ways to implement asynchronous requests, among whichstartAsync()It is a common usage. However, when we need to access in an asynchronous threadHttpServletRequestThere may be some problems whenHttpServletRequestThe life cycle of the thread is bound to the thread, while asynchronous threads usually cannot inherit the request context of the main thread.

This article will analyze this problem in detail from the following aspects and provide solutions:

  • Why is HttpServletRequest not accessible in an asynchronous thread?
  • Tomcat's request multiplexing mechanism and its impact
  • The role and limitations of AsyncContext
  • Correct use of RequestContextHolder
  • Complete solution

1. Source of the problem: Why is HttpServletRequest not accessible in asynchronous threads?

1. Request context and thread binding

HttpServletRequestis bound to the current request thread. Typically, the Servlet container assigns a thread to each HTTP request and processes the request within that thread. in this case,HttpServletRequestIt belongs to the main thread. When the request processing is completed, the Servlet container clears the request object.

However, in asynchronous request processing mode, the main thread and the asynchronous thread are different threads. By default, the asynchronous thread cannot access the request object in the main thread. The reason is:

  • Thread isolation: The context between the asynchronous thread and the main thread is isolated, and the asynchronous thread cannot automatically inherit the request context of the main thread.
  • Lifecycle issuesHttpServletRequestThe life cycle of the request processing thread is usually bound to the request processing thread, and it is cleared when the request processing is completed.

2. Frequently Asynchronous Threads Access Request Objects

  • Asynchronous thread initially cannot be accessedHttpServletRequest: When executing, the asynchronous thread does not automatically inherit the request context of the main thread. Therefore, it is directly passed in the asynchronous thread()When obtaining the request object, the return value isnull, resulting in inaccessibilityHttpServletRequest
  • Accessible in a short time, then unavailable: In usestartAsync()Tomcat delays when starting an asynchronous threadHttpServletRequestClearing of objects. This means that if the asynchronous thread iscomplete()Execution starts before being called, and may still be accessibleHttpServletRequest. But oncecomplete()Being called,HttpServletRequestIt will be cleared, and the asynchronous thread can no longer access the request object.
  • The request object cannot be accessed after clearing:once()When called, the request object will be cleared and the asynchronous thread will no longer be accessed.HttpServletRequest

2. Tomcat's request multiplexing mechanism and its impact

1. Tomcat request object multiplexing mechanism

Tomcat uses a request object multiplexing mechanism when processing requests. To improve performance, Tomcat reuses request objects to reduce memory creation and destruction overhead. This mechanism is usually used in high concurrency environments to improve server processing efficiency. Under the multiplexing mechanism, Tomcat caches some request objects and reuses them during the life cycle of the same request.

However, this multiplexing mechanism does not affect the life cycle of the requested object. When the request is processed in the main thread, the HttpServletRequest object is destroyed and cannot be used across threads. Therefore, although Tomcat may reuse certain objects, it does not continue to be provided to the asynchronous thread after the lifecycle of the request is over.

2. Life cycle and cleaning mechanism of request object

In Tomcat,HttpServletRequestThe life cycle of the request is managed by the processing thread of the request. When a request arrives, Tomcat will assign it a thread to process it, and when the request is processed, Tomcat will clear the request object. For asynchronous requests, Tomcat delays the destruction of the request object until the asynchronous task is completed and calledcomplete()

In usestartAsync()When starting an asynchronous thread, Tomcat sets a "delayed destruction" state for the request object until all asynchronous tasks are completed.This means that asynchronous threads cancomplete()Access the request object before being called, because the request object has not been cleared yet.

3. The impact of AsyncContext

AsyncContextis an object used to support asynchronous processing, which passesstartAsync()Method creation. Its function is to delay the clearance of the requested object until the asynchronous task is completed. Call()After that, Tomcat will release the request object, and at this time the asynchronous thread will not be able to access any data in the request object.

This is why, when an asynchronous thread is executed, a limitation of the request parameters can be accessed.If the asynchronous thread is()Access the request object before being called, and it can obtain the request data normally. Otherwise, it will not be able to access this data.

3. The role and limitations of AsyncContext

The role of ()

startAsync()The method is used to initiate asynchronous processing, which creates aAsyncContextinstance and delay the destruction of the requested object. By callingstartAsync(), Tomcat will delay the clearance of the requested object until it is called()

Example:startAsync()Delay request cleaning

public String handleRequest(HttpServletRequest request, HttpServletResponse response) {
    AsyncContext asyncContext = (request, response);
    new Thread(() -> {
        try {
            String age = ("name");
            ("Name accessed in an asynchronous thread: " + age);
            // Execute the export task            // Need to explicitly pass request to a method in an asynchronous thread            exportData(request);
            (); // Delay request cleaning        } catch (InterruptedException e) {
            ();
        }
    }).start();
    return "success";
}
 /**
   * Simulate export tasks
   */
private void exportData(HttpServletRequest request) {
    // You can continue to access request within exportTask    String userId = ("userId");
    ("The userId obtained in the exportData method: " + userId);
}

In this example,startAsync()DelayedHttpServletRequestThe object is destroyed, so the asynchronous thread iscomplete()The request object can be accessed before execution.
Key points:

Can't be directly retrieved in asynchronous threadsrequest
Asynchronous threads and main threads are different threads. By default, asynchronous threads cannot directly access the main thread's HttpServletRequest object. Therefore, we need to explicitly pass request to the asynchronous thread, or useRequestContextHolderPass the request context to the asynchronous thread.

Delayed cleaning request
()This ensures that the request object will not be cleaned during the asynchronous thread execution, ensuring that the asynchronous thread can access the request. If not calledcomplete(), the request object will be cleaned at the end of the request, causing the asynchronous thread to be inaccessiblerequest

Pass request to other methods
ifexportTaskIf you need to access the data in the request, you need toexportTaskInternal explicit passrequest, as in the examplerequestPassed as parameters toexportDatamethod.

2. AsyncContextLimitations of

  • Request cleaning time: Asynchronous threads can access the request object until it is called(). oncecomplete()When called, Tomcat will destroy the request object, and the asynchronous thread will no longer be accessed.HttpServletRequestNow.
  • Unable to automatically inherit request context:even thoughstartAsync()Delays request cleaning, it does not automatically pass the request context in the main thread to the asynchronous thread. This means that it is called directly in an asynchronous thread()When you get the request context, it will returnnull, because the request context is not passed.

4. Correct use of RequestContextHolder

In order to access the request object in an asynchronous thread, we need to explicitly pass the request context to the asynchronous thread. This can be done()to achieve and throughinheritable=trueEnsure that the request context can be passed to the asynchronous thread.

1. Pass the request context

When starting an asynchronous thread, we need to manually pass the request context into the asynchronous thread to ensure that it can access theHttpServletRequest. The specific method is through()Context pass.

Example: Use correctlyRequestContextHolder

private void executeExportTask(Runnable exportTask, String errorMessage) {
    HttpServletRequest req = (ServletRequestAttributes) ().getRequest();
    HttpServletResponse response = (ServletRequestAttributes) ().getResponse();
    // Manually pass the request context, set inheritable=true to ensure that the asynchronous thread inherits the request context of the main thread    ServletRequestAttributes attributes = new ServletRequestAttributes(req, response);
    (attributes, true);
    (() -> {
        try {
             // You can directly get the RequestContextHolder inside exportData            exportData();
        } catch (Exception e) {
            (errorMessage + e);
        } finally {
            // Clean up the request context to prevent memory leaks            ();
        }
    });
}

(attributes, true)The role of

  • Manually pass the request context:(attributes, true)The current request context is explicitly bound to the current thread (here is an asynchronous thread). In this way,RequestContextHolderWillHttpServletRequestandHttpServletResponsePassed into an asynchronous thread, allowing the asynchronous thread to access these request parameters.
  • inheritableSet astrueIt is key: it allows request context to propagate between threads, ensuring that asynchronous threads can access the request information of the main thread when needed.

2. Get the request context

In an asynchronous thread, we can pass()Get the request context of the current thread and get it from itHttpServletRequestObject. Assume that the exportData method implementation is like this:

 /**
   * Simulate export tasks
   */
private void exportData() {
    // Direct access() in exportData    HttpServletRequest request = (ServletRequestAttributes) ().getRequest();
    String userId = ("userId");
    ("The userId obtained in the exportData method: " + userId);
}

explain:

  • pleaseAsk for context delivery: by(attributes, true), explicitly pass the current request context to the asynchronous thread and ensure that it is inheritable.trueParameters indicate that the context will be passed to the child thread (asynchronous thread).
  • exportDataInternal access:exportDataDuring the mission,()Gets the request context of the current thread. This time you can access it safelyHttpServletRequest, get the request parameters.
  • Clean up the context: After the task is completed, pass()Clean up the request context and avoid memory leaks.

Why is this effective?

  • Thread context inheritance(attributes, true)Ensure that the current request context is passed into the asynchronous thread, so that the asynchronous thread can inherit the request context of the main thread. This is to implement that asynchronous threads can accessHttpServletRequestThe key.
  • Request parameter acquisition: Since the request context has been successfully bound to the asynchronous thread,exportDataInternal call()When it is available normallyHttpServletRequest, and read the request parameters from it.
  • Memory management: After each asynchronous task is executed, call it()The request context of the current thread can be cleaned to prevent possible memory leak problems.

5. Complete solution

1. Question review

  • Binding of request context and thread: In an asynchronous thread, HttpServletRequest cannot automatically inherit the request context of the main thread.
    • startAsync() mechanism to delay request cleaning:
    • startAsync() will delay the destruction of the request object, and asynchronous threads can access the request object before complete() is called. , but the request context is not automatically passed.

2. Best Practices

  • use()Manually pass the request context and set itinheritable=true, ensure that asynchronous threads can access the request object.
  • After the asynchronous thread is executed, remember to call it()Clean up the request context and avoid memory leaks.

Through the above method, you can ensure that you access correctly in asynchronous threadsHttpServletRequest, and avoid the impact of the cleanup of the request object on the asynchronous thread.

This is the end of this article about how to correctly use HttpServletRequest in Spring Boot in asynchronous threads. For more related content on Spring Boot using HttpServletRequest, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!