跨多个 <Host> 元素为公共库共享单个类加载器是否安全?

Is it safe to share a single Classloader for common libraries across multiple <Host> elements?

这是我在 Tomcat 中的 server.xml 文件的片段:

<Host name="client9001.example.com" appBase="/web/my-product-code" autoDeploy="true"></Host>
<Host name="client9002.example.com" appBase="/web/my-product-code" autoDeploy="true"></Host>
<Host name="client9003.example.com" appBase="/web/my-product-code" autoDeploy="true"></Host>
...
<Host name="client9254.example.com" appBase="/web/my-product-code" autoDeploy="true"></Host>

众所周知,每个 Host 元素都会创建自己的 WebappClassloader 实例,这使得每个主机都完全隔离和安全。通过此设置,我可以安全地使用一个 Tomcat 实例来为 X 个客户提供服务,每个客户都在不同的子域下提供服务。此设置可防止客户 A 的对象被客户 B 的操作所操纵。

但是,这对非堆 space 产生了不可扩展的需求(因为每个 class 都被加载了 X 次)我想知道我是否可以创建一个共享的 class 所有主机的加载程序。我知道 Tomcat 支持那种东西(在 https://tomcat.apache.org/tomcat-8.0-doc/class-loader-howto.html#Class_Loader_Definitions 中使用 "Common" class 加载程序)但我的问题是这样做是否安全。我的意思是,我可以通过消除所有静态字段来确保我自己的 classes 安全,但这就足够了吗?我担心第 3 方库,例如 Spring Framework、Log4J、Joda-time 和我的产品代码附带的其他几个库。

我已经使用反射来识别那些 classes 中的所有静态变量,我发现了 252 个静态和非最终字段和 5772 个静态和最终字段,仅此而已在第 3 方代码中(我自己的代码只有 3 个我将删除的字段)。

我应该沿着这条路走下去并检查所有那些 6027 个字段吗?我的意思是,这整个想法是个坏主意吗?如果是这样,那么在 "Common" class 加载程序中可以共享什么样的代码?

是否有任何强有力的证据表明所有这些著名的框架都可以安全地像这样共享,或者我应该将所有东西都视为不安全的,直到被证明不安全?

我会非常谨慎......并决定性能是否值得冒险

我在考虑使用共享类加载器可能会产生一些意想不到的后果的假设情况...

我查看了 Log4J,它通过 LogManager 创建了记录器,它扩展了 java.util.logging.LogManager,用于维护一组关于记录器和日志服务的共享状态。

想象一下这些客户端private static final Logger LOGGER = LogManager.getLogger();为每个主机

创建记录器的情况
 <Host name="client9001.example.com">  
 <Host name="client9002.example.com">
 <Host name="client9003.example.com"> 

 <Host name="BADclient.example.com"> 

因为 LogManager 在所有主机之间静态共享,恶意客户端可以调用 LogManagers.getLoggerNames();,这会 return 将所有已注册记录器的列表发送到该静态 LogManager 实例,并会泄露有关其他客户端的信息运行 在同一个 tomcat 实例上/能够删除使用相同 class 的其他主机的事件监听器(**我没试过这个**)

基本上,您希望将在所有主机(以及所有未来主机)之间 100% 共享的代码 运行 放在 JVM 上。常见的例子是初始化 JDBC 连接。

此外,在代码维护方面,如果您要深入研究,并尝试检查所有静态 methods/fields .. 每次更新第 3 方导入时,您都必须检查它们再次确保没有引入任何东西......甚至可能审查第三方进口的进口

可能会发现这个问题很有趣 Tomcat classloader violates delegating policy,因为他询问在 Tomcat

中使用普通 class 装载机的危险