Tomcat加載Spring-Web模塊時,SPI機制真的破壞了Java類加載器的可見性原則嗎?

Tomcat加載Spring-Web模塊時,SPI機制真的破壞了Java類加載器的可見性原則嗎?

tomcatspring-Web模塊加載:SPI機制下的類加載行為分析

Tomcat加載Spring-Web模塊時,利用Java SPI(Service Provider Interface)機制查找并使用ServletContainerInitializer接口的實現類。 這涉及到ServiceLoader的load方法和類加載器的可見性原則。 有人質疑這種方式違反了類加載器的可見性原則,讓我們深入分析。

文章指出,ServiceLoader.load方法最終由sun.misc.Launcher.AppClassLoader加載ServletContainerInitializer接口的實現類。代碼中,ServiceLoader.load(service, cl) 使用Thread.currentThread().getContextClassLoader() 獲取類加載器,在Tomcat等應用服務器中,該類加載器通常是AppClassLoader。

有人認為ServiceLoader.load(service, cl) 等同于 ServiceLoader.load(service, NULL)。雖然在某些情況下結果相似,但原理不同。前者明確指定類加載器,而后者使用調用者的類加載器。

立即學習Java免費學習筆記(深入)”;

為什么有人認為這破壞了類加載器的可見性原則?關鍵在于SPI機制的特殊性。rt.jar 中的接口由bootstrapClassLoader加載,但其實現類通常在classpath中,由AppClassLoader加載。BootstrapClassLoader無法向下委托加載,因此需要線程上下文類加載器加載實現類。 這繞過了雙親委派模型的嚴格層次,使AppClassLoader能夠加載BootstrapClassLoader無法加載的類。雖然解決了問題,但也偏離了雙親委派模型的本意。

需要強調的是,AppClassLoader并沒有直接跳過雙親委派機制的代碼,它內部仍然遵循雙親委派邏輯。只是在SPI場景下,由于BootstrapClassLoader的限制,最終加載工作由AppClassLoader完成,這是一種權衡之舉。 JDBC機制類似,Java只提供接口,具體實現由廠商提供,同樣需要繞過雙親委派機制的限制。

因此,SPI機制在某種程度上“違反”了雙親委派模型的嚴格規則,但這是一種必要的妥協,并非完全“破壞”了類加載器的可見性原則。它通過線程上下文類加載器找到了加載實現類的合適途徑。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享