设置属性时是否出现NullPointerException?

时间:2012-12-20 11:22:55

标签: java jsp servlets

例如,我有一个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)

5 个答案:

答案 0 :(得分:10)

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并因此被释放/销毁。

另见:

答案 1 :(得分:2)

Request的定义是线程安全的(与Session和ServletContext不同)。

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

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

答案 2 :(得分:1)

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

你得到的异常是NullPointerException,看起来Tomcat试图在null对象上调用一个方法。

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

答案 3 :(得分:1)

在没有此操作符的情况下使用

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

答案 4 :(得分:0)

如果你看一下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 ,但如果值为 null ,则只需从存储库中删除该密钥和旧关联对象。但如果它们都不是 null ,它们会将对象与该键关联,并将它们添加到存储库中。

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

有关实施的更多信息,请参阅以下链接 Source code of Request Implementation by tomcat