由于Tomcat可以一次加载多个Web应用程序,并且这些Web应用程序可以独立运行,并且不会互相干扰,因此它们可以在同一JVM中运行。因此,我对于tomcat如何在同一JVM中处理对象范围感到非常困惑。
例如,我在两个不同的Webapp中都有一个单例对象,并且tomcat将为每个生成两个不同的单例对象。我一直认为单例对象在同一JVM中只有一个对象,但是在tomcat JVM中可能有两个或更多。
我已经阅读了有关ClassLoader的一些信息,Tomcat具有自己的WebAppClassLoader来加载webapp。这是否意味着这里的Object Scope是ClassLoader还是我错了。有谁知道这件事,或者可以给我一些有关tomcat工作内存布局的信息吗?
所有秘密都在这些ClassLoader
实例的后面。
类的状态(如所有静态变量,字节码等)由类加载器确定,该类加载器加载该类(JVM中的类通过其完全限定的名称标识,而类加载器则加载该类。并非完全是一个范围,但作为范围的思考通常有助于更好地理解这一点。]
因此,如果一个类由两个不同的类加载器加载,则该类在VM中存在两次,它具有两组静态字段,可以具有不同的字节码(如不同的方法实现),并且都具有此类。请注意,即使两个对象的名称相同,也无法将它们强制转换。“普通” Java应用程序具有通过类加载器层次结构加载的所有类,并且每个类仅加载一次。
对于更复杂的情况,您将需要不同的行为。有时您想将库与代码混淆(例如eclipse中的插件或应用程序服务器中的Web应用程序)。
将程序与其他类隔离的基本思想是使用额外的类加载器加载那些类,并进行大量反射。如果您想阅读此内容,请查看ClassLoaders或OSGI上的Oracle文档。
Tomcat(以及许多其他Web容器/应用程序服务器)使用单独的ClassLoader层次结构加载应用程序。这样可以将所有类与其他(Web)应用程序隔离开,从而确保单例,不同的类版本以及所有这些东西不会冲突。
请记住,Java中的类由其完全限定名称
谈论单例时总是被遗忘的一件事是,单例只能有一个实例每个类加载器
在正常的Java应用程序中,当要求类加载器加载类时,它首先将请求委托给它的父类加载器,如果父类加载器找不到所请求的类,则将其加载。
对于Web应用程序服务器,这略有不同。对于部署在诸如tomcat之类的Web应用程序服务器中的每个Web应用程序,通常都有不同的类加载器。对于Tomcat来说,如下图所示-
JVM中类的“ ID”由完全限定的类名称和用于加载它的类加载器组成。这意味着,如果您通过不同的类加载器加载具有相同名称的两个类,它们将被视为不同的类。
因此,对于容器中的类加载器,单例将是单例-在容器/ JVM中;因为一个容器/ JVM可能具有多个类加载器。