tomcat与spring-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)。虽然在某些情况下结果相似,但原理不同。前者明确指定类加载器,而后者使用调用者的类加载器。
为什么有人认为这破坏了类加载器的可见性原则?关键在于spi机制的特殊性。rt.jar 中的接口由bootstrapclassloader加载,但其实现类通常在classpath中,由appclassloader加载。bootstrapclassloader无法向下委托加载,因此需要线程上下文类加载器加载实现类。 这绕过了双亲委派模型的严格层次,使appclassloader能够加载bootstrapclassloader无法加载的类。虽然解决了问题,但也偏离了双亲委派模型的本意。
需要强调的是,appclassloader并没有直接跳过双亲委派机制的代码,它内部仍然遵循双亲委派逻辑。只是在spi场景下,由于bootstrapclassloader的限制,最终加载工作由appclassloader完成,这是一种权衡之举。 jdbc机制类似,java只提供接口,具体实现由厂商提供,同样需要绕过双亲委派机制的限制。
因此,spi机制在某种程度上“违反”了双亲委派模型的严格规则,但这是一种必要的妥协,并非完全“破坏”了类加载器的可见性原则。它通过线程上下文类加载器找到了加载实现类的合适途径。
以上就是tomcat加载spring-web模块时,spi机制真的破坏了java类加载器的可见性原则吗?的详细内容,更多请关注代码网其它相关文章!
发表评论