设置属性时是否出现NullPointerException?

例如,我有一个servlet代码,它将属性设置为HttpServletRequest:

request.setAttribute("someValue", someValue()); RequestDispatcher rd = getServletContext().getRequestDispatcher("/SomeJsp.jsp"); rd.forward(this.request, this.response); return; 

如何确保上面的代码是线程安全的?

这是我得到的堆栈跟踪:

 java.lang.NullPointerException at org.apache.catalina.connector.Request.notifyAttributeAssigned(Request.java:1552) at org.apache.catalina.connector.Request.access$000(Request.java:105) at org.apache.catalina.connector.Request$3.set(Request.java:3342) at org.apache.catalina.connector.Request.setAttribute(Request.java:1504) at org.apache.catalina.connector.RequestFacade.setAttribute(RequestFacade.java:541) at org.apache.catalina.core.ApplicationHttpRequest.setAttribute(ApplicationHttpRequest.java:281) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:286) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684) at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:471) at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:402) at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:329) at com.mycompany.myapp.servlet.SomeServlet.doRequest(SomeServlet.java:103) at com.mycompany.myapp.servlet.SomeServlet.doGet(SomeServlet.java:159) 

 rd.forward(this.request, this.response); 

这(惩罚意图)表明您已将requestresponse分配为类的实例变量。 反过来,您的具体问题表明类本身的实例不是线程安全的。

假设它实际上是servlet本身,那么你就是问题的原因。 Servlet根本不是线程安全的。 在webapp启动期间只创建了一个实例,然后在整个应用程序范围内共享。

永远不应将请求或会话范围数据分配为servlet的实例变量。 只有在同一时间发生另一个HTTP请求时才会覆盖它。 这将使您的代码成为线程安全的,就像您自己遇到的那样。

这里有一些代码说明:

 public class MyServlet extends HttpServlet { private Object thisIsNOTThreadSafe; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Object thisIsThreadSafe; thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests! thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe. } } 

将HTTP请求本身分配为servlet的实例变量实际上是一个史诗般的错误。 当用户Y在servlet正在处理用户X的请求的同时触发另一个请求时,用户X将立即获得用户Y的requestresponse对象。 这绝对是线程安全的。 引起NPE是因为request是在那个时刻“完成”处理用户Y并因此被释放/销毁。

也可以看看:

  • servlet如何工作? 实例化,会话,共享变量和multithreading

根据它的定义,请求是线程安全的(与Session和ServletContext不同)。

关于例外:您使用的Tomcat版本是什么? 这看起来像一个Tomcat错误。

作为someValue()方法的返回类型的类是否实现了HttpAttributeBindingListener ? 并且, someValue()方法可以返回null吗? 如果两者都是,那么NullPointerException是显而易见的。

我不确定这与线程安全有什么关系。

您获得的exception是NullPointerException,看起来Tomcat正在尝试调用null对象上的方法。

在Java Web应用程序中,每个请求都有自己的HttpServletRequest实例,因此您可以在请求上设置属性,并确信它仅适用于该用户。

没有这个操作员使用

  RequestDispatcher rd = getServletContext().getRequestDispatcher("/SomeJsp.jsp"); rd.forward(request, response); return; 

如果你看看tomcat中的请求接口的实现,它看起来像下面的代码。

 public void setAttribute(String name, Object value) { // Name cannot be null if (name == null) throw new IllegalArgumentException (sm.getString("coyoteRequest.setAttribute.namenull")); // Null value is the same as removeAttribute() if (value == null) { removeAttribute(name); return; } if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { internalDispatcherType = (DispatcherType)value; return; } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { requestDispatcherPath = value; return; } 

清楚地看到,如果key为null,则抛出IllegalArgumentException,但如果value为null,则只需从reposatory中删除该键和旧的关联对象。 但如果它们都不为null ,它会将对象与该键关联,并将它们添加到存储库中。

这似乎是一个临时或tomcat问题。

有关实现的更多信息,请参阅下面的链接tomcat请求实现的源代码