【问题标题】:Usage of Static variables in Java Servlets (e.g. in AppEngine)Java Servlet 中静态变量的使用(例如在 AppEngine 中)
【发布时间】:2010-12-23 09:33:32
【问题描述】:

我有一个应用程序,其中 Servlet 有一个名为 Update(ReqIn, ReqOut) 的方法。我从doGet & doPost 调用它并传递请求和响应变量,然后由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();

现在的问题是: 在多用户环境(AppEngine 上的 Jetty)中,这会带来什么问题吗?例如。一些线程/竞赛问题使用户看到不正确的 IP 地址或在极端情况下突然以其他用户身份登录?

或者我应该重写代码并将其更改为Public UserClass User而不是Public static UserClass User等?

【问题讨论】:

    标签: java google-app-engine servlets jetty static-members


    【解决方案1】:

    使用静态是一个非常糟糕的主意,因为如果您同时收到两个请求,那么它们将相互覆盖。以这个简单的例子来看看会出现什么问题:

    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 行(包括第 5 行)。
    请求 2 进来,并完全处理。
    请求 1 继续处理。

    两个请求都会得到文本“2”,而不是一个得到“1”,一个得到“2”。这是一个简单的状态被踩的例子。

    现在,回答你问题的第二部分;

    或者我应该重写代码并将其更改为Public UserClass User而不是Public static UserClass User等?

    不,这也不够好,因为 J2EE 规范允许 servlet 容器使用类的一个实例来服务该 servlet 映射的所有请求,也就是说,实例级变量将具有完全相同的作为静态的效果,它们在所有请求之间共享。

    这只剩下三个真正的选择:

    1. 将所有内容推入 HTTPSession。这里的问题是,这是一张地图,因此您会失去类型安全性,并且很难看到正在使用的地方。
    2. 创建一个 Holder 类来保存您的所有状态并将其传递到任何地方。这稍微好一点,因为至少您不会失去类型安全性,但您仍然没有完全可见性。
    3. 传递各个必需的项目。

    【讨论】:

      【解决方案2】:

      是的,这是一个非常糟糕的主意!

      如果您同时收到两个请求,您期望会发生什么?每个静态变量只能保存一个值,因此您会丢失数据。

      可以使用ThreadLocal,这样每个线程只能访问它正在处理的当前请求/用户/等 - 但这基本上仍然是个坏主意。它很脆弱,并且隐藏了较低层需要信息的事实。将状态传递给需要它的代码。

      【讨论】:

      • @Downvoter:愿意给出理由吗?是不是认为使用静态是不好的,还是你可以(但不应该)使用 ThreadLocal?
      • servlet 传入请求和响应对象以捕获处理特定请求的状态。为什么要存储它的静态副本来处理请求?或者,为什么要尝试在请求之间存储它的静态副本?这不是明智之举。
      • @JonSkeet(顺便说一句,同意你的观点。)
      猜你喜欢
      • 2011-04-07
      • 1970-01-01
      • 1970-01-01
      • 2018-12-24
      • 2012-01-19
      • 2012-09-12
      • 2016-02-07
      • 1970-01-01
      相关资源
      最近更新 更多