Tomcat类加载器如何在同一个JVM中分离不同的Webapps对象作用域?

时间:2013-10-24 07:07:53

标签: java tomcat jvm

由于Tomcat可以同时加载多个webapp,并且这些webapp可以单独工作,并且不会互相干扰,并且它们可以在同一个JVM中工作。 所以我对tomcat如何在同一个JVM中处理Object作用域感到很困惑。

例如,我在两个不同的Web应用程序中都有一个单例对象,而tomcat将为每个Web应用程序生成两个不同的单例对象。我一直认为单例对象在同一个JVM中只有一个对象,但在tomcat JVM中可能有两个或更多。


我已经阅读了有关ClassLoader的一些信息,Tomcat有自己的WebAppClassLoader来加载webapps。那么这意味着这里的对象范围是ClassLoader还是我错了。有没有人知道这个或者可以给我一些关于tomcat工作内存布局的信息?

7 个答案:

答案 0 :(得分:30)

所有秘密都在ClassLoader个实例背后。

类的状态(像所有静态变量,字节代码等)由加载该类的类加载器确定范围(类由其名称和加载类的类加载器标识。这不完全是范围,但考虑范围通常有助于更好地理解这一点。

因此,如果一个类由两个不同的类加载器加载,则该类在VM中存在两次,它具有两组静态字段,可以具有不同的字节代码(如不同的方法实现)以及所有这些。 “普通”Java应用程序具有由类加载器层次结构加载的所有类,并且每个类仅加载一次。

对于更复杂的场景,您将需要不同的行为。有时你想隔离一个库而不是弄乱你的代码(比如eclipse中的插件或应用服务器中的web应用程序)。

将程序与其他类隔离的基本思想是加载具有额外类加载器的程序并使用大量反射。如果您想阅读此内容,请查看有关ClassLoadersOSGI的Oracle文档。

Tomcat(以及许多其他Web容器/应用程序服务器)使用单独的ClassLoader层次结构加载应用程序。这将所有类与其他(Web)应用程序隔离开来,从而也确保单例,不同类版本以及所有这些内容不会发生冲突。

答案 1 :(得分:10)

请记住,Java中的类由完全限定名称 加载它的类加载器标识。 Tomcat为您部署的每个上下文(Web应用程序)使用单独的类加载器,从而将它们分开。此外,系统类加载器加载tomcat特定的库,JVM引导程序加载器加载Java核心库。

答案 2 :(得分:6)

在谈论单身人士时总会遗漏一件事,就是单身人士只能有一个实例每个类加载器ClassLoader限制了类的可见性,因此同一个VM中的几个不同的类加载器下可以存在相同的类。除了其他方面,这允许您同时加载不同版本的jar。

这个问题:Java Class Loaders似乎有一些很好的链接和资源可供进一步研究。

答案 3 :(得分:4)

在普通的Java应用程序中,当要求类加载器加载一个类时,它会将请求委托给它的父类加载器,然后在父类加载器找不到所请求的类时加载它。

对于Web应用程序服务器,这略有不同。对于像tomcat这样的Web应用程序服务器中部署的每个Web应用程序,通常都有不同的类加载器。对于Tomcat,它看起来像下面 -

enter image description here

因此,对于Web应用程序类,加载资源按以下顺序发生 -

  1. JVM的引导类(核心java类)
  2. / WEB-INF /您的Web应用程序的类
  3. 您的Web应用程序的
  4. / WEB-INF / lib / * .jar
  5. 系统类加载器类(Tomcat / Classpath特定类)
  6. 常见的类加载器类(所有Web应用程序通用的类)
  7. 但请注意,如果Web应用程序类加载器配置了delegate="true",则订单会更改 -

    1. JVM的引导类(核心java类)
    2. 系统类加载器类(Tomcat / Classpath特定类)
    3. 常见的类加载器类(所有Web应用程序通用的类)
    4. / WEB-INF /您的Web应用程序的类
    5. 您的Web应用程序的
    6. / WEB-INF / lib / * .jar
    7. 有关详细信息,您可以查看Apache Tomcat的Class Loader HOW-TO页面。

答案 4 :(得分:2)

JVM中类的“ID”由完全限定的类名和用于加载它的类加载器组成。这意味着,如果您使用不同的类加载器加载两个具有相同名称的类,则它们将被视为不同的类。

答案 5 :(得分:0)

因此,单例将是类加载器的单例 - 在容器/ JVM中;因为容器/ JVM可能有多个类加载器。

答案 6 :(得分:0)

  1. 使用不同的类加载器分离tomcat中的不同应用程序。例如app1使用ClassLoaderA,app2使用classloaderB。
  2. 每个类都将使用自己的类加载器来加载其他类。因此,如果ClassA.class引用ClassB.class,则ClassB需要位于ClassA或其父类的类加载器的类路径中。例如,在app1中,从ClassLoaderA加载com.exmaple.test1。 com.exmaple.test1想要新的com.exmaple.test2()。默认情况下,它使用自己的类加载器ClassLoaderA来加载com.exmaple.test2。因此,在com.exmaple.test1的视图中,它只能看到自己的类路径类(app1 / webapp / classes或app1 / webapp / lib)。在app2中,它会看到不同的视图。
  3. 总结一下学习类加载器,您必须了解委托模型。而能见度是孩子可以看到的父母。但是父母看不到孩子和兄弟姐妹看不到兄弟姐妹。所以我们可以隔离不同的应用程序。