英文:
Is Tomcat 9 common classloader a URLClassLoader?
问题
I have a custom library used by all of my applications that usually resides in the common library set of catalina.properties. It assumes that the classloader is a URLClassLoader.
在所有我的应用程序中都使用的自定义库通常位于catalina.properties的公共库集中。它假设类加载器是URLClassLoader。
Under Java 8 even the basic AppClassLoader could be cast to URLClassLoader, and so could the classloader used by Tomcat 8 (which I suspect was a custom classloader made by the Tomcat designers).
在Java 8中,即使是基本的AppClassLoader也可以强制转换为URLClassLoader,Tomcat 8使用的类加载器也可以这样做(我怀疑这是Tomcat设计者制作的自定义类加载器)。
So, under Java 9-11, in Tomcat 9... can I expect the common classloader to be a URLClassLoader? If not, what is it? And would there be a way for me to design a URLClassloader that could be plugged in to make common use it?
那么,在Java 9-11中,在Tomcat 9中... 我可以期望common类加载器是URLClassLoader吗? 如果不是,它是什么?是否有一种方法可以设计一个URLClassloader,可以插入以使common使用它?
Thanks. 感谢。
英文:
I have a custom library used by all of my applications that usually resides in the common library set of catalina.properties. It assumes that the classloader is a URLClassLoader.
Under Java 8 even the basic AppClassLoader could be cast to URLClassLoader, and so could the classloader used by Tomcat 8 (which I suspect was a custom classloader made by the Tomcat designers).
So, under Java 9-11, in Tomcat 9... can I expect the common classloader to be a URLClassLoader? If not, what is it? And would there be a way for me to design a URLClassloader that could be plugged in to make common use it?
Thanks.
答案1
得分: 2
以下是翻译好的部分:
TL;DR: Tomcat 9的常见类加载器是URLClassLoader
。
要检查Tomcat应用程序使用哪些类加载器,请创建一个小的servlet来列出ClassLoader
层次结构。
@WebServlet("/testcl")
public class ClassLoaderTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
for (ClassLoader cl = Thread.currentThread().getContextClassLoader(); cl != null; cl = cl.getParent()) {
out.println(cl.getClass().getName());
if (cl instanceof URLClassLoader)
for (URL url : ((URLClassLoader) cl).getURLs())
out.println(" " + url);
}
}
}
部署到Tomcat并打开servlet的页面,例如http://localhost:8080/test/testcl
。
显示的页面列出了类加载器以及如果类加载器是URLClassLoader
的话列出的URL。
如下所示,输出中可以看到webapp类加载器和common类加载器都是URLClassLoader
:
-
输出中的第一个是Tomcat WebApp 类加载器,列出了
test
webapp的WEB-INF/classes
文件夹。如果存在的话,它还会列出WEB-INF/lib
文件夹中的任何jar文件。它是一个URLClassLoader
。 -
输出中的第二个是Tomcat Common 类加载器,列出了Tomcat
lib
文件夹和该文件夹中找到的所有jar文件。它是一个URLClassLoader
。 -
输出中的第三个是Java App 类加载器,表示Java应用程序的CLASSPATH。在Java 8及之前的版本中,它是一个
URLClassLoader
。在Java 9及以后的版本中,它不再是一个简单的URLClassLoader
,因为有了模块系统。 -
输出中的第四个是Java Extension/Platform 类加载器。在Java 8及之前的版本中,它是一个
URLClassLoader
。在Java 9及以后的版本中,它不再是一个简单的URLClassLoader
,因为有了模块系统。 -
没有显示在输出中,因为它由
null
值表示,是Java Bootstrap 类加载器。
Java 8的示例输出
org.apache.catalina.loader.ParallelWebappClassLoader
file:/C:/prog/tomcat-9.0.27/webapps/test/WEB-INF/classes/
java.net.URLClassLoader
file:/C:/prog/tomcat-9.0.27/lib/
file:/C:/prog/tomcat-9.0.27/lib/annotations-api.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-ant.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-ha.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-storeconfig.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-tribes.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina.jar
file:/C:/prog/tomcat-9.0.27/lib/ecj-4.13.jar
file:/C:/prog/tomcat-9.0.27/lib/el-api.jar
file:/C:/prog/tomcat-9.0.27/lib/jasper-el.jar
file:/C:/prog/tomcat-9.0.27/lib/jasper.jar
file:/C:/prog/tomcat-9.0.27/lib/jaspic-api.jar
file:/C:/prog/tomcat-9.0.27/lib/jsp-api.jar
file:/C:/prog/tomcat-9.0.27/lib/servlet-api.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-api.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-coyote.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-dbcp.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-cs.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-de.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-es.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-fr.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ja.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ko.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-pt-BR.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ru.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-zh-CN.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-jdbc.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-jni.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-util-scan.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-util.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-websocket.jar
file:/C:/prog/tomcat-9.0.27/lib/websocket-api.jar
sun.misc.Launcher$AppClassLoader
file:/C:/prog/tomcat-9.0.27/bin/bootstrap.jar
file:/C:/prog/tomcat-9.0.27/bin/tomcat-juli.jar
sun.misc.Launcher$ExtClassLoader
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/access-bridge-64.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/cldrdata.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/dnsns.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/jaccess.jar
<details>
<summary>英文:</summary>
***TL;DR:** The common classloader of Tomcat 9 is a `URLClassLoader`*
To check which classloaders are used by a Tomcat application, create a small servlet to list the `ClassLoader` hierarchy.
```lang-java
@WebServlet("/testcl")
public class ClassLoaderTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
for (ClassLoader cl = Thread.currentThread().getContextClassLoader(); cl != null; cl = cl.getParent()) {
out.println(cl.getClass().getName());
if (cl instanceof URLClassLoader)
for (URL url : ((URLClassLoader) cl).getURLs())
out.println(" " + url);
}
}
}
Deploy to Tomcat and open the page of the servlet, e.g. http://localhost:8080/test/testcl
The shown page lists the classloaders and the URLs if the classloader is a URLClassLoader
.
As can be seen in the output below, both the webapp classloader and the common classloader are URLClassLoader's:
-
The 1st in the output is the Tomcat WebApp classloader, listing the
WEB-INF/classes
folder of thetest
webapp. It would also have listed any jar files in theWEB-INF/lib
folder, if there had been any.
It is aURLClassLoader
. -
The 2nd in the output is the Tomcat Common classloader, listing the Tomcat
lib
folder and all the jar files found in that folder.
It is aURLClassLoader
. -
The 3rd in the output is the Java App classloader, representing the CLASSPATH of the Java application.
In Java 8 and earlier, it is aURLClassLoader
. In Java 9 and later, it is not a simpleURLClassLoader
any more, because of the Module system. -
The 4rd in the output is the Java Extension/Platform classloader.
In Java 8 and earlier, it is aURLClassLoader
. In Java 9 and later, it is not a simpleURLClassLoader
any more, because of the Module system. -
Not shown in output, because it is represented by the
null
value, is the Java Bootstrap classloader.
Sample output with Java 8
org.apache.catalina.loader.ParallelWebappClassLoader
file:/C:/prog/tomcat-9.0.27/webapps/test/WEB-INF/classes/
java.net.URLClassLoader
file:/C:/prog/tomcat-9.0.27/lib/
file:/C:/prog/tomcat-9.0.27/lib/annotations-api.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-ant.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-ha.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-storeconfig.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-tribes.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina.jar
file:/C:/prog/tomcat-9.0.27/lib/ecj-4.13.jar
file:/C:/prog/tomcat-9.0.27/lib/el-api.jar
file:/C:/prog/tomcat-9.0.27/lib/jasper-el.jar
file:/C:/prog/tomcat-9.0.27/lib/jasper.jar
file:/C:/prog/tomcat-9.0.27/lib/jaspic-api.jar
file:/C:/prog/tomcat-9.0.27/lib/jsp-api.jar
file:/C:/prog/tomcat-9.0.27/lib/servlet-api.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-api.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-coyote.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-dbcp.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-cs.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-de.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-es.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-fr.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ja.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ko.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-pt-BR.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ru.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-zh-CN.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-jdbc.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-jni.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-util-scan.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-util.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-websocket.jar
file:/C:/prog/tomcat-9.0.27/lib/websocket-api.jar
sun.misc.Launcher$AppClassLoader
file:/C:/prog/tomcat-9.0.27/bin/bootstrap.jar
file:/C:/prog/tomcat-9.0.27/bin/tomcat-juli.jar
sun.misc.Launcher$ExtClassLoader
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/access-bridge-64.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/cldrdata.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/dnsns.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/jaccess.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/jfxrt.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/localedata.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/nashorn.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/sunec.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/sunjce_provider.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/sunmscapi.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/sunpkcs11.jar
file:/C:/prog/Java64/jdk1.8.0_181/jre/lib/ext/zipfs.jar
Sample output with Java 14
org.apache.catalina.loader.ParallelWebappClassLoader
file:/C:/prog/tomcat-9.0.27/webapps/test/WEB-INF/classes/
java.net.URLClassLoader
file:/C:/prog/tomcat-9.0.27/lib/
file:/C:/prog/tomcat-9.0.27/lib/annotations-api.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-ant.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-ha.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-storeconfig.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina-tribes.jar
file:/C:/prog/tomcat-9.0.27/lib/catalina.jar
file:/C:/prog/tomcat-9.0.27/lib/ecj-4.13.jar
file:/C:/prog/tomcat-9.0.27/lib/el-api.jar
file:/C:/prog/tomcat-9.0.27/lib/jasper-el.jar
file:/C:/prog/tomcat-9.0.27/lib/jasper.jar
file:/C:/prog/tomcat-9.0.27/lib/jaspic-api.jar
file:/C:/prog/tomcat-9.0.27/lib/jsp-api.jar
file:/C:/prog/tomcat-9.0.27/lib/servlet-api.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-api.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-coyote.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-dbcp.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-cs.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-de.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-es.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-fr.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ja.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ko.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-pt-BR.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-ru.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-i18n-zh-CN.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-jdbc.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-jni.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-util-scan.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-util.jar
file:/C:/prog/tomcat-9.0.27/lib/tomcat-websocket.jar
file:/C:/prog/tomcat-9.0.27/lib/websocket-api.jar
jdk.internal.loader.ClassLoaders$AppClassLoader
jdk.internal.loader.ClassLoaders$PlatformClassLoader
答案2
得分: -1
Tomcat 9仍然使用URLClassLoader用于common和以后的类加载器。
确定方法:
-
初步测试已经确认web应用程序使用了URLClassLoader。但由于Tomcat使用它自己的ClassLoader来启动web应用程序,这并不能回答Tomcat在达到web应用程序初始化阶段之前发生了什么。
-
因此,要在web应用程序初始化阶段之前识别common类加载器使用的ClassLoader,我不得不使用一些奇怪的技巧:
- 切换Tomcat的日志记录到log4j
- 创建一个自定义的appender
- 将自定义appender放置在common库中
- 配置log4j.xml以使用自定义appender
- 在appender中添加代码以显示由appender使用的ClassLoader的名称和类。
- 由于log4j日志记录在Tomcat初始化任何Web应用程序之前被激活,正如log4j的条目所示... 这回答了这个问题。
希望这个答案对那些在Java 9及更高版本中遇到同样问题的人有所帮助,他们在谷歌搜索时可能会找到这个答案。
英文:
ANSWER:
Tomcat 9 still uses URLClassLoader for the common and later classloaders.
METHOD OF DETERMINATION:
-
The initial tests with a webapp had already confirmed that webapps used a URLClassLoader. But since Tomcat launches webapps with their own ClassLoader, that does not answer what happens... before Tomcat reaches the webapp initialization stage.
-
So, to identify the classloader used by the common classloader before the webapp initialization stage I had to use some weird tricks:
- Switched Tomcat logging to log4j
- Created a custom appender
- Placed the custom appender in the common library
- Configured log4j.xml to use the custom appender
- Added code to the appender to display the name and class of the classloader used by the appender.
- Since log4j logging gets activated by Tomcat before initializing any web applications, as demonstrated by the log4j entries... it answers the question.
I hope this answer is useful to those that stumble onto the same problem with Java 9 and later, and arrive to it when they google.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论