java ThreadLocal 在 servlet 中存储 ServletRequest 和 Response:有什么用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5473077/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 11:16:59  来源:igfitidea点击:

ThreadLocal to store ServletRequest and Response in servlet: what for?

javajakarta-eeservletsthread-local

提问by glaz666

Once I have came across a pattern, where ServletRequestand response objects are put to servlet's local ThreadLocalvariables. The servlet class has also methods to get current request and response objects. So in order to get these objects you still need to operate with servlet object.

一旦我遇到了一个模式,其中ServletRequest和响应对象被放置到 servlet 的局部ThreadLocal变量。servlet 类还有获取当前请求和响应对象的方法。所以为了得到这些对象,你还是需要对servlet对象进行操作。

What is the point of having these ThrealLocallocal variables?

拥有这些ThrealLocal局部变量有什么意义?

回答by Bozho

The point is to have the request and response objects in classes that would otherwise would not have them (for example they are not servlets). One example are JSF managed beans - their methods do not take HttpServletRequestparameters, and so you can obtain the request via the FacesContext, which has them in ThreadLocalvariables.

关键是在类中包含请求和响应对象,否则它们将不会包含它们(例如它们不是 servlet)。一个例子是 JSF 托管 bean - 它们的方法不接受HttpServletRequest参数,因此您可以通过 获取请求FacesContext,其中将它们放在ThreadLocal变量中。

The reason this works is because each request is handled by a separate thread (by the servlet container). So thread = request. But there is a caveat - containers tend to use thread pools. So one must always set a fresh request in the threadlocal, and preferably clean it up afterwards (for example in a Filter). Otherwise you can get some unexpected behaviour.

这样做的原因是因为每个请求都由一个单独的线程(由 servlet 容器)处理。所以线程=请求。但是有一个警告——容器倾向于使用线程池。因此,必须始终在 threadlocal 中设置一个新的请求,并且最好在之后对其进行清理(例如在 a 中Filter)。否则你会得到一些意想不到的行为。

But you should really avoid this in your code. If you need anything from the request or response, pass it as method argument around. Otherwise you risk to violate layer boundaries (if you are tempted to use the request in the service layer, for example)

但是你真的应该在你的代码中避免这种情况。如果您需要请求或响应中的任何内容,请将其作为方法参数传递。否则,您可能会违反层边界(例如,如果您想在服务层中使用请求)

回答by DaveH

They allow you to gain access to the HttpServletRequest and HttpServletResponse from other classes within your project without having to pass references to these objects to the other classes. It's not a pattern I particularly like as it tends to mix up your web tier code with your business logic and makes unit testing more difficult.

它们允许您从项目中的其他类访问 HttpServletRequest 和 HttpServletResponse,而不必将这些对象的引用传递给其他类。这不是我特别喜欢的一种模式,因为它倾向于将您的 Web 层代码与您的业务逻辑混淆,并使单元测试更加困难。

回答by Sanjay T. Sharma

Others have pretty much stated what is the use of Thread Locals in the scenario you presented. But be warned though, Thread Local relying implementations are "thread" specific and break when things move away from a single thread per request model. Example would be event based servers wherein a handful of threads are used for lots of user requests concurrently.

其他人几乎已经说明了在您呈现的场景中线程局部变量的用途。但是请注意,线程本地依赖的实现是“线程”特定的,并且当每个请求模型从单个线程移开时就会中断。示例是基于事件的服务器,其中少量线程同时用于大量用户请求。

回答by Dead Programmer

Purpose of ThreadLocal ?

ThreadLocal 的目的?

when you have some object that is not thread-safe, but you want to avoid synchronizing access to that object ( SimpleDateFormat). Instead, give each thread its own instance of the object.

当您有一些不是线程安全的对象,但您想避免同步访问该对象 (SimpleDateFormat) 时。相反,给每个线程它自己的对象实例。

You need to be very careful about cleaning up any ThreadLocals you get()or set()by using the ThreadLocal's remove()method.

您需要非常小心地清理任何 ThreadLocalsget()set()使用 ThreadLocal 的remove()方法。

回答by gpeche

Since the request and the response objects are stored in thread local variables, you get thread safe access to those objects without having to pass them around as method parameters.

由于请求和响应对象存储在线程局部变量中,因此您可以线程安全地访问这些对象,而不必将它们作为方法参数传递。

Example 1: Without thread local

示例 1:没有线程本地

public class MyServlet extends Servlet {
    private MyObject myObject = new MyObject();

    public void service(ServletRequest request, ServletResponse response) {
        myObject.doSomething(request, response);
    }
}

public class MyObject {
    private MyOtherObject myOtherObject = new MyOtherObject();
    public void doSomething(ServletRequest request, ServletResponse response) {
        // I do nothing with request/response, but need to accept them in order
        // to pass them to myOtherObject
        myOtherObject.doSomethingElse(request, response);
    }
}

public class MyOtherObject {
    public void doSomethingElse(ServletRequest request, ServletResponse response) {
        // Do something else with request / response
    }
}

Example 2: with thread local

示例 2:使用线程本地

public class MyServlet extends Servlet {
    private MyObject myObject = new MyObject();

    private static ThreadLocal<ServletRequest> currentRequest = new ThreadLocal<ServletRequest>();

    public static ServletRequest getCurrentRequest() {
        return currentRequest.get();
    }

    private static ThreadLocal<ServletResponse> currentResponse = new ThreadLocal<ServletResponse>();

    public static ServletResponse getCurrentResponse() {
        return currentResponse.get();
    }

    public void service(ServletRequest request, ServletResponse response) {
        ...
        currentRequest.set(request);
        currentResponse.set(response);
        ...
        myObject.doSomething();
    }
}

public class MyObject {
    private MyOtherObject myOtherObject = new MyOtherObject();
    public void doSomething() {
        // I do not need to know about request / response as I do nothing with them
        myOtherObject.doSomethingElse();
    }
}

public class MyOtherObject {
    public void doSomethingElse() {
        // Now I can get the current request / response in a thread safe
        // manner and without having to accept them as parameters
        ServletRequest request = MyServlet.getCurrentRequest();
        ServletResponse response = MyServlet.getCurrentResponse();

        // Do something with request / response
    }
}

Obviously, for simple servlets just passing the objects around is the easiest thing, but in complex scenarios it is sometimes useful to have one static but thread safe getter.

显然,对于简单的 servlet 来说,仅仅传递对象是最简单的事情,但在复杂的场景中,有时拥有一个静态但线程安全的 getter 是有用的。

回答by inor

This is really terrible. You should obtain the values you need from the HTTP request/session as soon as you possibly can. you can pass these values in method invocations or Transfer Objects. you should strive to write methods/classes technology-free. if your method/class obtains an http request from ThreadLocal it's a worthless class - it's no longer useful in any any non-http context.

这真的很可怕。您应该尽快从 HTTP 请求/会话中获取所需的值。您可以在方法调用或传输对象中传递这些值。您应该努力编写无技术的方法/类。如果您的方法/类从 ThreadLocal 获取 http 请求,则它是一个毫无价值的类 - 它在任何非 http 上下文中都不再有用。

It's especially shocking to me to see people pull http requests from ThreadLocal in BOs (Business Objects) or DAOs. HTTP requests should never appear in any layer other than the presentation layer of the application.

看到人们从 BO(业务对象)或 DAO 中的 ThreadLocal 拉取 http 请求,这让我特别震惊。HTTP 请求不应出现在应用程序的表示层以外的任何层中。

回答by Ramakrishna

I think the better case can be like..

我认为更好的情况可以像..

Connection object once created in Service layer put in ThreadLocal then call a DAO layer, get connection object from Threadlocal.

在Service层创建的连接对象放入ThreadLocal然后调用DAO层,从Threadlocal获取连接对象。

回答by Tomasz B?achowicz

I'm not 100% sure what was the intention of the author of the code you'd once came across, but I guess the idea there is that ServletRequestinstance is available from any method in the code without passing it as parameter or setting as instance variable. Usually ThreadLocalvariable is static and there is a method exposed that allows to obtain the instance of ServletRequestin statically. For instance you could access ServletRequestin Struts FromBeans easily using this technique.

我不是 100% 确定您曾经遇到过的代码作者的意图是什么,但我想这个想法ServletRequest是可以从代码中的任何方法获得该实例,而无需将其作为参数传递或设置为实例多变的。通常ThreadLocal变量是静态的,并且公开了一个允许ServletRequest静态获取in实例的方法。例如,您可以ServletRequest使用此技术轻松访问Struts FromBeans。