Tomcat 类加载器的顺序:common、shared 和 server

Posted

技术标签:

【中文标题】Tomcat 类加载器的顺序:common、shared 和 server【英文标题】:Order of Tomcat Classloaders: common, shared, and server 【发布时间】:2011-09-09 10:30:40 【问题描述】:

Tomcat Class Loader HOW-TO 文档描述了 4 种不同的类加载器:

    引导程序 系统 常见 Web 应用程序

然而,在默认的 catalina.properties 文件中,也有为共享和服务器类加载器定义的属性。在文件的默认版本中,这两个属性都是空的,并且 cmets 说:

如果留空,“通用”加载器 将用作卡特琳娜的 “共享”/“服务器”加载器。

我无法找到有关这些类加载器的任何其他文档。我的问题是,共享加载程序和系统加载程序相对于公共加载程序的搜索顺序是什么?此外,这些类加载器的预期用途是什么?

【问题讨论】:

另见***.com/questions/5474765/… 【参考方案1】:

我最近也遇到了这个问题,这就是我发现的,(这都是来自 Tomcat 7 主干)

如果留空,“通用”加载器将用作 Catalina 的“共享”/“服务器”加载器。

这里是相关的source,

89      private void initClassLoaders() 
90          try 
91              commonLoader = createClassLoader("common", null);
92              if( commonLoader == null ) 
93                  // no config file, default to this loader - we might be in a 'single' env.
94                  commonLoader=this.getClass().getClassLoader();
95              
96              catalinaLoader = createClassLoader("server", commonLoader);
97              sharedLoader = createClassLoader("shared", commonLoader);
98           catch (Throwable t) 
99              handleThrowable(t);
100             log.error("Class loader creation threw exception", t);
101             System.exit(1);
102         
103     

106     private ClassLoader createClassLoader(String name, ClassLoader parent)
107         throws Exception 
108 
109         String value = CatalinaProperties.getProperty(name + ".loader");
110         if ((value == null) || (value.equals("")))
111             return parent;

因此,如果未定义任何内容,它们将回退到使用 common.loader 条目。


关于它们的加载顺序, 这是加载它们的来源,来自source

229         Thread.currentThread().setContextClassLoader(catalinaLoader);
230 
231         SecurityClassLoad.securityClassLoad(catalinaLoader);
232 
233         // Load our startup class and call its process() method
234         if (log.isDebugEnabled())
235             log.debug("Loading startup class");
236         Class<?> startupClass =
237             catalinaLoader.loadClass
238             ("org.apache.catalina.startup.Catalina");
239         Object startupInstance = startupClass.newInstance();
240 
241         // Set the shared extensions class loader
242         if (log.isDebugEnabled())
243             log.debug("Setting startup class properties");
244         String methodName = "setParentClassLoader";
245         Class<?> paramTypes[] = new Class[1];
246         paramTypes[0] = Class.forName("java.lang.ClassLoader");
247         Object paramValues[] = new Object[1];
248         paramValues[0] = sharedLoader;
249         Method method =
250             startupInstance.getClass().getMethod(methodName, paramTypes);
251         method.invoke(startupInstance, paramValues);

229行设置common.loader类加载器,然后251行设置shared.loader类加载器设置为Catalinas父类加载器。

【讨论】:

链接已失效 感谢@Hearen,修复了链接。【参考方案2】:

同意 mindas,apache tomcat 小组可能正在考虑弃用服务器和共享类加载器。关于webappclassloader和standardclassloader(common class loader)的顺序,有简波做的一篇有趣的帖子。他做了一个简单的测试来证明这一点。 http://web.archive.org/web/20120303091507/http://www.jianbozhu.net/2012/02/14/tomcat-classloader-demonstration/

基本上它的要点是在tomcat中,类加载器首先从webapp加载类,然后是shared/common,然后是system。

【讨论】:

【参考方案3】:

奇怪,Tomcat 5.5 classloader doc 仍然记录了 shared 加载程序,但 6.0 doesn't;您引用的 v7.0 也没有。也许他们会弃用它?

我们确实广泛使用共享加载器来覆盖我们软件的香草版本附带的现有类。我们制作的软件以版本形式发布并为一个客户制作一个完整的新版本(例如,这需要一个关键的错误修复)太昂贵(重新测试所有内容、重建、提供新文档、新版本号等)。所以我们要做的是提供一个“修补程序”,它进入共享加载器并覆盖 webapp 中的相关.class

大多数情况下,“修补程序”只是一个类,因此整体回归风险很小。

当我们的软件升级时,升级会删除“修补程序”,因为更正的代码也将出现在我们软件本身的下一版本中。

我还可以想象其他人使用共享类加载器来生成跨许多不同 web 应用程序的东西。

【讨论】:

那么,@mindas,您是说共享类加载器实际上是在 webapp 类加载器之前搜索的?这似乎不对。

以上是关于Tomcat 类加载器的顺序:common、shared 和 server的主要内容,如果未能解决你的问题,请参考以下文章

06-阿里面试题:Tomcat类加载设计 [线程上下文类加载器+破坏性双亲委派机制]

Tomcat打破双亲委派机制执行顺序底层代码原理JVM04_Tomcat JDBC破坏双亲委派机制带来的面试

还是Tomcat,关于类加载器的趣味实验

Tomcat源码篇自定义类加载器那点儿事儿

Tomcat中jar包和class的加载顺序

tomcat类加载机制了解一下