问题
Once I have came across a pattern, where ServletRequest
and response objects are put to servlet's local ThreadLocal
variables. 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.
What is the point of having these ThrealLocal
local variables?
回答1:
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 HttpServletRequest
parameters, and so you can obtain the request via the FacesContext
, which has them in ThreadLocal
variables.
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.
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)
回答2:
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.
回答3:
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.
回答4:
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
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
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.
回答5:
Purpose of 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.
You need to be very careful about cleaning up any ThreadLocals you get()
or set()
by using the ThreadLocal's remove()
method.
回答6:
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 ServletRequest
instance is available from any method in the code without passing it as parameter or setting as instance variable. Usually ThreadLocal
variable is static and there is a method exposed that allows to obtain the instance of ServletRequest
in statically. For instance you could access ServletRequest
in Struts FromBeans easily using this technique.
回答7:
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.
回答8:
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.
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.
来源:https://stackoverflow.com/questions/5473077/threadlocal-to-store-servletrequest-and-response-in-servlet-what-for