Servlet容器是否可以防止Web应用程序相互干扰,它们是如何做到的?

2022-09-04 08:07:21

我知道一个 servlet 容器,比如 Apache Tomcat,在 JVM 的单个实例中运行,这意味着它的所有 servlet 都将在同一进程中运行。

我还知道,Servlet容器的架构意味着每个Web应用程序都存在于自己的上下文中,这表明它与其他Web应用程序是隔离的。

如下图所示:alt text

接受每个Web应用程序都是隔离的,我希望您可以创建相同Web应用程序的2个副本,更改每个副本的名称和上下文路径(以及任何其他相关配置),并并行运行它们,而不会影响另一个副本。这个问题的答案似乎支持这一观点。

然而,一位同事根据他们尝试这样做的经验而不同意。

他们采用了一个Web应用程序,并尝试在同一个servlet容器中运行2个单独的实例(具有不同的名称等),并遇到了2个实例冲突的问题(我无法详细说明,因为我没有参与该工作)。

基于此,他们认为,由于Web应用程序在同一进程空间中运行,因此它们不能被隔离,并且诸如类属性之类的东西最终会被无意中共享。这个答案似乎暗示了同样的事情

这两种视图似乎不兼容,所以我问你:servlet容器是否能防止部署到同一容器的Web应用程序相互冲突?

如果他们如何做到这一点?

如果不是为什么会发生干扰?

最后,在什么情况下,单独的Web应用程序会发生冲突并导致彼此干扰?,也许是涉及文件系统上的资源,本机代码或数据库连接的情况?


答案 1

简短的答案是,servlet 容器通过为每个应用程序使用单独的类装入器来隔离应用程序 - 由单独的类装入器装入的类(即使来自相同的物理类文件)彼此不同。但是,类装入器共享一个公共的父类装入器,并且容器可以提供许多其他容器范围的资源,因此应用程序之间并不完全隔离。

例如,如果两个应用程序共享一些公共代码,每个应用程序在其战争中都包含相同的jar,则每个应用程序将从jar中加载自己的类实例,并且一个应用程序中的类的静态变量(例如单例)将不同于另一个应用程序中相同类的静态变量。

现在,以应用程序尝试使用的应用程序为例(并且可能在其 war 文件中不包含自己的 Logger 类实例)。每个应用程序自己的类装入器在 war 文件中找不到该类,因此它们将遵从其父类装入器,该类装入器可能是共享的容器范围的类装入器。父类装入器将装入 Logger 类,然后两个应用程序将共享同一个 Logger 类。java.util.Logger


答案 2

同一容器中的 Servlet 将共享一些资源。我认为应该可以在同一容器中部署相同的Web应用程序两次,前提是您为每个应用程序指定不同的名称,并且它们不会在特定资源上发生冲突。从理论上讲,这与部署两个不同的 servlet 相同,它们恰好具有相同的实现,而我们一直在这样做。

一些共享资源,在我的头顶上(我不是专家,所以不要引用任何这些!

  • tomcat/common/lib (Tomcat 5) 或 tomcat/lib (Tomcat 6) 中的 Libraries (jars)。
  • 全局服务器中的设置.xml、Web.xml、tomcat-users.xml
  • 操作系统提供了一些东西,例如stdin/stdout/stderr,网络套接字,设备,文件等。
  • 日志记录系统。
  • Java system properties (System.getProperty(), System.setProperty())
  • 我怀疑...静态变量?我不确定ClassLoader设计是否会阻止这种情况。
  • 记忆。这是最常见的问题:一个 servlet 可以通过消耗所有内存来拒绝其他 servlet 的可用性。
  • CPU - 尤其是多线程应用程序。在HotSpot JVM上,每个Java线程实际上是一个操作系统级线程,这很昂贵,你不需要超过几千个。

毫无疑问,还有更多。

其中许多内容都受到安全管理器的保护,如果您使用的是安全管理器。


推荐