问题1:
我们知道,当一个类加载器即将加载一个类时,它会将请求委托给它的父类加载器。但是在Tomcat中,它不会:您可以加载您的类来覆盖放在通用lib目录中的同一个名称类。这意味着Tomcat WebappClassloader
不遵循委派策略。这违反了惯例吗?
问题2: 我写了一个类并将其放在通用的lib目录中,显然这个类是在web应用程序之间共享的。例如,每个Web应用程序都可以读取/写入类的静态字段。此外,JDK中的类由Bootstrap类加载器加载,然后它们的静态字段由任何Web应用程序共享,这是危险的吗?
答案 0 :(得分:6)
此行为是故意的,它允许您在每个WAR中独立覆盖Tomcat本身提供的库。例如,您可以使用部署到容器的每个应用程序的不同版本覆盖Log4J,而不会引入任何问题或破坏其他应用程序。来自Tomcat documentation:
与许多服务器应用程序一样,Tomcat安装了各种类加载器,以便允许容器的不同部分以及容器上运行的Web应用程序,以便具有访问权限到可用类和资源的不同存储库。此机制用于提供Servlet规范2.4版中定义的功能 - 特别是9.4和9.6节。
它确实违反了正常的委派算法,但这也是其他应用程序服务器的工作方式(例如JBoss)。
广告。问题2 :是的,它很危险,您必须记住同步并且无法控制谁修改此变量。我会完全避免static
个字段。
例如EhCache允许您分享CacheManager
。这是通过net.sf.ehcache.CacheManager#singleton
static volatile
字段实现的。现在你遇到了各种各样的问题:如果你将ehcache.jar
放在Tomcat的/lib
中,它将按预期工作。但是,如果每个Web应用程序都有自己的JAR文件副本,则共享将不起作用,因为每个Web应用程序都有自己的CacheManager
类副本。当只有一个应用程序有自己的ehcache.jar
时,它会变得更糟 - 所有应用程序将共享CachedManager
的同一个实例,除了将ehcache.jar
打包在一起的应用程序。这种错误很难追查......