Использование статических переменных в сервлетах Java (например, в AppEngine) - PullRequest
0 голосов
/ 04 декабря 2009

У меня есть приложение, в котором сервлет имеет метод с именем Update(ReqIn, ReqOut). Я вызываю его из doGet & doPost и передаю переменные Request и Response, а затем до Update(...) заполняю следующие статические переменные:

...
public class Server extends HttpServlet {

    public static HttpServletRequest In = null;
    public static HttpServletResponse Out = null;

    public static boolean isDebug = true;
    public static boolean isPost = false;

    public static String URL = "";
    public static String IP = "0.0.0.0";
    public static Cookie[] Cookies = null;

    public static UserClass User = null;
    public static boolean isLoggedIn = false;


    ...
}

В основном, абстрагирование наиболее часто используемых вещей и обновление их при каждом запросе. Это также позволяет мне получать доступ к IP-адресу и текущим данным пользователя из любой точки веб-сайта, просто записывая Server.User.getUsername(); вместо создания нового экземпляра Class при каждой загрузке страницы и используя гораздо более длинный код доступа: Server.getUser().getUsername();

Теперь вопрос: Может ли это вызвать проблемы в многопользовательской среде (Jetty на AppEngine)? Например. какие-то проблемы с многопоточностью / гонками, из-за которых пользователь видит неправильный IP-адрес или, в крайнем случае, неожиданно входит в систему как другой пользователь?

Или я должен переписать код и изменить его на Public UserClass User вместо Public static UserClass User и т. Д.

Ответы [ 2 ]

7 голосов
/ 05 декабря 2009

Использование статики - очень плохая идея, поскольку, если вы получаете два запроса одновременно, они будут переписываться друг с другом. Возьмите этот тривиальный пример, чтобы увидеть, что может пойти не так:

1:public class Server extends HttpServlet {
2:  public static int requestNo = 0;
3:  public void doGet(HttpServletRequest req, HttpServletResponse resp)
4:  {
5:     requestNo++;
6:     resp.getWriter().println(requestNo);
7:  }
8:}

Теперь представьте себе следующую временную шкалу:

Запрос 1 поступает и обрабатывает до и включительно строки 5.
Запрос 2 поступает и обрабатывается полностью.
Запрос 1 продолжает обработку.

Оба запроса получат текст «2» вместо одного, получающего «1», и одного, получающего «2». Это простой пример того, как государство наступает.

Теперь, чтобы ответить на вторую часть вашего вопроса;

Или я должен переписать код и изменить его на Public UserClass User вместо Public static UserClass User и т. Д.?

Нет, это тоже недостаточно, поскольку спецификация J2EE позволяет контейнеру сервлета использовать один экземпляр класса для обслуживания всех запросов для этого отображения сервлета, то есть переменные уровня экземпляра будут иметь точно такие же как статические, они распределяются между всеми запросами.

Это оставляет только три реальных варианта:

  1. Запихните все в HTTPSession. Проблема здесь в том, что это карта, поэтому вы теряете безопасность типов, и трудно понять, где что-то используется.
  2. Создайте класс Holder для хранения всего вашего состояния и передавайте его везде. Это немного лучше, так как, по крайней мере, вы не потеряете безопасность типов, но у вас все еще нет полной видимости.
  3. Раздайте отдельные необходимые предметы.
6 голосов
/ 04 декабря 2009

Да, это очень плохая идея!

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

Вы могли бы использовать ThreadLocal, чтобы каждый поток имел доступ только к текущему запросу / пользователю / и т. Д., С которым он имел дело - но это по-прежнему плохая идея. Он хрупкий и скрывает тот факт, что информация нужна нижним уровням. Вместо этого передайте состояние в код, который нуждается в нем.

...