NullPointerException при установке атрибута?

например, у меня есть код сервлета, который устанавливает атрибут HttpServletRequest:

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

Как убедиться, что приведенный выше код является потокобезопасным?

Это stacktrace, который я получаю:

java.lang.NullPointerException
    at org.apache.catalina.connector.Request.notifyAttributeAssigned(Request.java:1552)
    at org.apache.catalina.connector.Request.access0(Request.java:105)
    at org.apache.catalina.connector.Request.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 ответов


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

это (каламбур) предполагает, что вы назначили request и response как переменные экземпляра класса. Ваша конкретная проблема, в свою очередь, предполагает, что экземпляр самого класса не является потокобезопасным.

предполагая, что это на самом деле сам сервлет, тогда у вас есть причина вашей проблемы. Сервлеты не являются threadsafe на всех. Существует только один экземпляр этого был создан во время запуска webapp, который затем совместно используется через все запросы applicationwide.

вы должны никогда назначить данные запроса или сеанса в качестве переменной экземпляра сервлета. Он будет переопределен только тогда, когда другой HTTP-запрос происходит в тот же момент. Это сделает ваш код threadunsafe, как вы столкнулись сами.

вот некоторый код, который иллюстрирует, что:

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-запроса в качестве переменной экземпляра сервлета на самом деле является эпической ошибкой. Когда пользователь Y запускает другой запрос в то же время сервлет имеет дело с запросом пользователя X, тогда пользователь X мгновенно получит request и response объекты пользователя Y в руки. Это, безусловно, threadunsafe. NPE вызван тем, что request в этот момент "закончен" с обработкой для пользователя Y и, таким образом, выпущен/уничтожен.

Читайте также:


запрос является потокобезопасным по его определению (в отличие от сеанса и ServletContext).

Что касается исключения: какую версию Tomcat вы используете? Это похоже на ошибку Tomcat.

делает класс, который является возвращаемым типом someValue() способ реализации HttpAttributeBindingListener? И, может someValue() метод return null? Если оба да, то NullPointerException - это очевидно.


Я не уверен, что это связано с его потокобезопасным.

исключение, которое вы получаете, является NullPointerException похоже, что Tomcat пытается вызвать метод для нулевого объекта.

в веб-приложении Java каждый запрос имеет свой собственный экземпляр 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;
    }

его ясно видно, что если ключ равен null, то он бросает IllegalArgumentException но если значение null потом просто удалить ключ и старые Связанный объект с ключом от reposatory. Но если ни один из них null их он свяжет объект с этим ключом и добавит их в репозиторий.

это кажется временным или проблема с tomcat.

для получения дополнительной информации о реализации см. ссылку ниже исходный код реализации запроса tomcat