在Java Servlet中使用静态变量(例如在AppEngine中)

时间:2009-12-04 20:34:26

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

我有一个应用程序,其中Servlet有一个名为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();每次加载页面时使用新的类实例,并使用更长的访问代码:Server.getUser().getUsername();

现在问题是:当处于多用户环境(AppEngine上的Jetty)时,这会引入任何问题吗?例如。一些线程/赛车问题让用户看到不正确的IP地址,或者在极端情况下突然以不同的用户身份登录?

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

2 个答案:

答案 0 :(得分:7)

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

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. 传递所需的个别物品。

答案 1 :(得分:6)

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

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

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