开发者

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

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?


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)


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.


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.


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.


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜