Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ThreadLocal将ServletRequest和响应存储在servlet中:用于什么?_Java_Jakarta Ee_Servlets_Thread Local - Fatal编程技术网

Java ThreadLocal将ServletRequest和响应存储在servlet中:用于什么?

Java ThreadLocal将ServletRequest和响应存储在servlet中:用于什么?,java,jakarta-ee,servlets,thread-local,Java,Jakarta Ee,Servlets,Thread Local,一旦我遇到了一种模式,ServletRequest和响应对象被放置到servlet的本地ThreadLocal变量中。servlet类还有获取当前请求和响应对象的方法。所以,为了获得这些对象,您仍然需要使用servlet对象进行操作 拥有这些threalllocal局部变量有什么意义 它们允许您从项目中的其他类访问HttpServletRequest和HttpServletResponse,而无需将对这些对象的引用传递给其他类。这不是一种我特别喜欢的模式,因为它往往会将web层代码与业务逻辑混合

一旦我遇到了一种模式,
ServletRequest
和响应对象被放置到servlet的本地
ThreadLocal
变量中。servlet类还有获取当前请求和响应对象的方法。所以,为了获得这些对象,您仍然需要使用servlet对象进行操作


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

它们允许您从项目中的其他类访问HttpServletRequest和HttpServletResponse,而无需将对这些对象的引用传递给其他类。这不是一种我特别喜欢的模式,因为它往往会将web层代码与业务逻辑混合在一起,使单元测试变得更加困难。

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

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


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

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

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


使用ThreadLocal的
remove()
方法清理
get()
set()
中的任何ThreadLocal时需要非常小心。

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

示例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
    }
}
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
    }
}
示例2:使用线程本地

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
    }
}
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
    }
}
公共类MyServlet扩展Servlet{
私有MyObject MyObject=新MyObject();
私有静态ThreadLocal currentRequest=新ThreadLocal();
公共静态ServletRequest getCurrentRequest(){
返回currentRequest.get();
}
私有静态ThreadLocal currentResponse=new ThreadLocal();
公共静态ServletResponse getCurrentResponse(){
返回currentResponse.get();
}
公共作废服务(ServletRequest请求、ServletResponse响应){
...
currentRequest.set(请求);
currentResponse.set(响应);
...
myObject.doSomething();
}
}
公共类MyObject{
私有MyOtherObject MyOtherObject=新的MyOtherObject();
公共无效剂量测定法(){
//我不需要知道请求/响应,因为我对它们不做任何事情
myOtherObject.doSomethingElse();
}
}
公共类对象{
公共无效doSomethingElse(){
//现在我可以在线程安全的环境中获取当前请求/响应
//方式,而不必接受它们作为参数
ServletRequest=MyServlet.getCurrentRequest();
ServletResponse=MyServlet.getCurrentResponse();
//对请求/响应做些什么
}
}

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

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

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


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

我认为更好的情况是


一旦在服务层创建了连接对象,将其放入ThreadLocal,然后调用DAO层,从ThreadLocal获取连接对象。

@matt b-我不明白你的意思。请求和响应存储在threadlocals中,因此没有其他线程可以干扰我在GWT RemoteServiceServlet中遇到的东西,我想知道他们为什么这样做。在深入研究代码之后,我意识到它们提供了额外的接口供您的应用程序实现