一旦我遇到一个模式,ServletRequest
和响应对象放在servlet的本地ThreadLocal
变量中。 servlet类还有获取当前请求和响应对象的方法。因此,为了获得这些对象,您仍然需要使用servlet对象。
拥有这些ThrealLocal
局部变量有什么意义?
答案 0 :(得分:16)
关键是在类中包含请求和响应对象,否则它们将不具有它们(例如它们不是servlet)。一个例子是JSF托管bean - 他们的方法不接受HttpServletRequest
参数,因此您可以通过FacesContext
获取请求,ThreadLocal
包含Filter
个变量。
这样做的原因是因为每个请求都由一个单独的线程(由servlet容器)处理。所以thread = request。但有一点需要注意 - 容器倾向于使用线程池。因此必须始终在threadlocal中设置一个新的请求,最好在之后清理它(例如在{{1}}中)。否则你会得到一些意想不到的行为。
但是你应该在代码中避免这种情况。如果您需要请求或响应中的任何内容,请将其作为方法参数传递。否则,您可能会违反图层边界(例如,如果您想在服务图层中使用该请求)
答案 1 :(得分:3)
它们允许您从项目中的其他类访问HttpServletRequest和HttpServletResponse,而无需将对这些对象的引用传递给其他类。这不是我特别喜欢的模式,因为它往往会将您的Web层代码与您的业务逻辑混淆,并使单元测试更加困难。
答案 2 :(得分:2)
其他人已经在你提出的场景中详细说明了Thread Locals的用途。但是要注意,Thread Local依赖实现是特定于“线程”的,并且当每个请求模型从一个线程移开时会中断。示例将是基于事件的服务器,其中少数线程同时用于大量用户请求。
答案 3 :(得分:1)
当你有一些不是线程安全的对象,但你想避免同步对该对象的访问(SimpleDateFormat)。相反,为每个线程提供自己的对象实例。
您需要非常小心,使用ThreadLocal的get()
方法清除set()
或remove()
的任何ThreadLocals。
答案 4 :(得分:1)
由于请求和响应对象存储在线程局部变量中,因此您可以通过线程安全访问这些对象,而无需将它们作为方法参数传递。
示例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
}
}
示例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
}
}
显然,对于简单的servlet来说,只传递对象是最容易的事情,但在复杂的情况下,有一个静态但线程安全的getter有时很有用。
答案 5 :(得分:0)
我不是100%确定你曾经遇到过的代码作者的意图是什么,但我想这里的想法是ServletRequest
实例可以从代码中的任何方法获得而没有将其作为参数传递或设置为实例变量。通常ThreadLocal
变量是静态的,并且有一个暴露的方法允许静态获取ServletRequest
的实例。例如,您可以使用此技术轻松访问Struts FromBeans中的ServletRequest
。
答案 6 :(得分:0)
我认为情况会更好。
在Service层中创建的连接对象一旦放入ThreadLocal,然后调用DAO层,即可从Threadlocal获取连接对象。
答案 7 :(得分:-1)
这太可怕了。您应该尽快从HTTP请求/会话中获取所需的值。您可以在方法调用或传输对象中传递这些值。你应该努力编写无技术的方法/类。如果你的方法/类从ThreadLocal获得一个http请求它是一个毫无价值的类 - 它在任何任何非http上下文中都不再有用。
看到人们在BO(Business Objects)或DAO中从ThreadLocal中提取http请求,这让我感到特别震惊。 HTTP请求不应出现在应用程序表示层以外的任何层中。