0

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

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

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

4

2 回答 2

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. 传递各个所需的项目。
于 2009-12-04T21:31:55.093 回答
6

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

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

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

于 2009-12-04T20:36:52.390 回答