You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Elgs Chen <el...@hotmail.com> on 2012/09/25 14:19:09 UTC
WebClassLoader using SystemClassLoader to load ServletDef?
Dear Tomcat Developers,
I have a question regarding the behavior of the WebClassLoader.loadClass(String name, boolean resolve) in the org.apache.catalina.loader package.
I have the following assumptions, please correct me if any is wrong:
1, It seems the WebClassLoader only uses the SystemClassLoader (or AppClassLoader) to loader tomcat core classes, like ServletDef;
2, It seems if tomcat is started up by the startup.sh from the bin directory, the classpath in the startup command line will include only the jars in the bin directory: bootstrap.jar, commons-daemon.jar and tomcat-juli.jar;
3, ClassLoader.getSystemClassLoader() by default returns the class loader with the startup command-line classpath;
Now if the above three assumption are correct, it seems that it's not possible for the WebClassLoader to load the tomcat core classes as only the few bootstrap jars are in the system class loader's classpath. However, the fact is the startup.sh script indeed starts tomcat up. Why?
For this I wrote some test code. My idea is to write a very simple bootstrap class(Bootstrap) which creates an instance of URLClassLoader, the instance of URLClassLoader has all jars shipped with the embedded tomcat 7.0.30. This classloader then loads another Class(TomcatMain), then instantiates it and calls its main method reflectively to start it up. The purpose of doing so is to save the effort to modify classpath in the startup script each time new jars are added. My Bootstrap class looks something like this:
public static void main(String[] args) throws Exception {
List<File> jarList = new ArrayList<File>();
System.out.println(getServerHome());
getClassPath(jarList, new File(getServerHome(), "lib"));
URL[] urlList = toURL(jarList);
URLClassLoader loader = new URLClassLoader(urlList);
Class c = loader.loadClass(args[0]);
Method m = c.getMethod("main", new Class[] { args.getClass() });
String[] appArgs = new String[args.length - 1];
System.arraycopy(args, 1, appArgs, 0, args.length - 1);
m.invoke(null, new Object[] { appArgs });
}
And the TomcatMain looks something like this:
public static void main(String[] args) throws Exception {
if (args[0].indexOf("start") != -1) {
System.out.println("Self:" + TomcatMain.class.getClassLoader());
System.out.println("Parent:" + TomcatMain.class.getClassLoader().getParent());
String appBase = getServerHome() + "/web";
final Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
//...
}
}
Then I pack the Bootstrap in loader.jar, running the following command from the command-line:
java -cp loader.jar Bootstrap TomcatMain start
I get the following error output:
Self:java.net.URLClassLoader@60ec2ea8
Parent:sun.misc.Launcher$AppClassLoader@e776f7
...
SEVERE: End event threw exception
java.lang.ClassNotFoundException: org.apache.catalina.deploy.ServletDef
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
at org.apache.tomcat.util.IntrospectionUtils.callMethod1(IntrospectionUtils.java:852)
...
Then I debug into the WebClassLoader, it turned out that the SystemClassLoader is not able to load the ServletDef class. And it looks reasonable, as the system class loader should be the one that I put the few bootstrap jars in the command line, as the assumption 2 implies. Seems The WebClassLoader doesn't intend to load the ServletDef from the URLClassLoader created by the Bootstrap at all.
To further prove what I thought, I tried to start up the TomcatMain directly from the command line, with all embedded tomcat shipped jars in the command line classpath. This time it works. Tomcat started up successfully, with the following output:
Self:sun.misc.Launcher$AppClassLoader@492833ff
Parent:sun.misc.Launcher$ExtClassLoader@6e6dcfde
This time, it uses the system(app) class loader to load the ServletDef, which enclosing jar is in the command line classpath. So far, that proved what I guess.
So my question is:
How does the startup.sh shipped with tomcat binary make the WebClassLoader to load the ServletDef?
Thanks,
Elgs
Re: WebClassLoader using SystemClassLoader to load ServletDef?
Posted by Mark Thomas <ma...@apache.org>.
On 25/09/2012 16:04, Elgs Chen wrote:
> Hi Mark,
>
> Thanks for your fast answer. That helped me to narrow down the scope of this problem. I understand line 262 is to initialize and create the common, shared and catalina class loaders. But I'm still struggling how the WebappClassLoader.loadClass(String name, boolean resolve) be able to load the class ServletDef. Can you please give me some more insight into this method? I think the it should load the class via the catalina class loader as my previous assumption 1 was wrong. If this is the case, How does this method achieve that?
This is beginning to sound like a homework question. I suggest you look
at the source code for the WebappClassLoader and/or trace through the
code using a debugger.
Mark
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
Re: WebClassLoader using SystemClassLoader to load ServletDef?
Posted by Elgs Chen <el...@hotmail.com>.
Hi Chris,
Thanks for reminding. I'm fully aware of the separating to protecting mechanism, and some classes are loaded from top to down, like those starting with java and javax, and some are prohibited to be loaded from the webapp class loaders, like the servlet API classes like ServletDef, others are bottom to up. Actually I think I'm just doing the similar thing as what Tomcat is doing. I'm creating my URLClassLoader while Tomcat is creating the common class loader. So I think my instance of URLClassLoader is just a simple counterpart of the common class loader. And above them is the system/app class loader.
Would you correct me if my understanding is not accurate?
Best regards,
Elgs
On Sep 26, 2012, at 3:19 AM, Christopher Schultz <ch...@christopherschultz.net> wrote:
> Elgs,
>
> On 9/25/12 1:15 PM, Elgs Chen wrote:
>> Hi Mark,
>>
>> I finally get my homework done. Thank you so much for pointing me to the right direction. That really helped me to gain huge insight into the inner world of the tomcat.
>>
>> I used JPDA to attach my eclipse to tomcat. Then I was able to see everything happens with the WebappClassLoader.loadClass. For my question, the key is to set the WebappClassLoader's parent class loader. Previously it was the system class loader, which is not intended. As this became obvious, I added a line to set the server's parent class loader, like this:
>>
>> final StandardServer server = (StandardServer) tomcat.getServer();
>> server.setParentClassLoader(TomcatMain.class.getClassLoader());
>>
>> Now the server's parent class loader becomes my URLClassLoader, and that is the class loader being able to load all the jars I put in the lib directory. Then I start my Bootstrap, it works like a charm!!
>>
>> Mark, thank you so much. I really really appreciate you fast and kind help!
>
> Note that Tomcat separates ClassLoaders in this way to protect
> "system"-level classes from being loaded by web applications. By
> changing the parent ClassLoader, you are undoing that protection.
>
> -chris
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
Re: WebClassLoader using SystemClassLoader to load ServletDef?
Posted by Christopher Schultz <ch...@christopherschultz.net>.
Elgs,
On 9/25/12 1:15 PM, Elgs Chen wrote:
> Hi Mark,
>
> I finally get my homework done. Thank you so much for pointing me to the right direction. That really helped me to gain huge insight into the inner world of the tomcat.
>
> I used JPDA to attach my eclipse to tomcat. Then I was able to see everything happens with the WebappClassLoader.loadClass. For my question, the key is to set the WebappClassLoader's parent class loader. Previously it was the system class loader, which is not intended. As this became obvious, I added a line to set the server's parent class loader, like this:
>
> final StandardServer server = (StandardServer) tomcat.getServer();
> server.setParentClassLoader(TomcatMain.class.getClassLoader());
>
> Now the server's parent class loader becomes my URLClassLoader, and that is the class loader being able to load all the jars I put in the lib directory. Then I start my Bootstrap, it works like a charm!!
>
> Mark, thank you so much. I really really appreciate you fast and kind help!
Note that Tomcat separates ClassLoaders in this way to protect
"system"-level classes from being loaded by web applications. By
changing the parent ClassLoader, you are undoing that protection.
-chris
Re: WebClassLoader using SystemClassLoader to load ServletDef?
Posted by Elgs Chen <el...@hotmail.com>.
Hi Mark,
I finally get my homework done. Thank you so much for pointing me to the right direction. That really helped me to gain huge insight into the inner world of the tomcat.
I used JPDA to attach my eclipse to tomcat. Then I was able to see everything happens with the WebappClassLoader.loadClass. For my question, the key is to set the WebappClassLoader's parent class loader. Previously it was the system class loader, which is not intended. As this became obvious, I added a line to set the server's parent class loader, like this:
final StandardServer server = (StandardServer) tomcat.getServer();
server.setParentClassLoader(TomcatMain.class.getClassLoader());
Now the server's parent class loader becomes my URLClassLoader, and that is the class loader being able to load all the jars I put in the lib directory. Then I start my Bootstrap, it works like a charm!!
Mark, thank you so much. I really really appreciate you fast and kind help!
Best regards,
Elgs
On Sep 25, 2012, at 11:04 PM, Elgs Chen <el...@hotmail.com> wrote:
> Hi Mark,
>
> Thanks for your fast answer. That helped me to narrow down the scope of this problem. I understand line 262 is to initialize and create the common, shared and catalina class loaders. But I'm still struggling how the WebappClassLoader.loadClass(String name, boolean resolve) be able to load the class ServletDef. Can you please give me some more insight into this method? I think the it should load the class via the catalina class loader as my previous assumption 1 was wrong. If this is the case, How does this method achieve that?
>
> Many thanks,
> Elgs
>
>
> On Sep 25, 2012, at 9:28 PM, Mark Thomas <ma...@apache.org> wrote:
>
>> On 25/09/2012 13:19, Elgs Chen wrote:
>>> Dear Tomcat Developers,
>>>
>>> I have a question regarding the behavior of the WebClassLoader.loadClass(String name, boolean resolve) in the org.apache.catalina.loader package.
>>>
>>> I have the following assumptions, please correct me if any is wrong:
>>> 1, It seems the WebClassLoader only uses the SystemClassLoader (or AppClassLoader) to loader tomcat core classes, like ServletDef;
>>
>> Wrong. See [1].
>>
>>> 2, It seems if tomcat is started up by the startup.sh from the bin directory, the classpath in the startup command line will include only the jars in the bin directory: bootstrap.jar, commons-daemon.jar and tomcat-juli.jar;
>>
>> Correct.
>>
>>> 3, ClassLoader.getSystemClassLoader() by default returns the class loader with the startup command-line classpath;
>>
>> Correct.
>>
>>> Now if the above three assumption are correct, it seems that it's not possible for the WebClassLoader to load the tomcat core classes as only the few bootstrap jars are in the system class loader's classpath. However, the fact is the startup.sh script indeed starts tomcat up. Why?
>>
>> The logical conclusion would be that one or more of the assumptions is
>> wrong.
>>
>>
>>> So my question is:
>>> How does the startup.sh shipped with tomcat binary make the WebClassLoader to load the ServletDef?
>>
>> See [2], line 262.
>>
>> Mark
>>
>>
>> [1] http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
>> [2]
>> http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Bootstrap.java?view=annotate
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: dev-help@tomcat.apache.org
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
>
>
Re: WebClassLoader using SystemClassLoader to load ServletDef?
Posted by Elgs Chen <el...@hotmail.com>.
Hi Mark,
Thanks for your fast answer. That helped me to narrow down the scope of this problem. I understand line 262 is to initialize and create the common, shared and catalina class loaders. But I'm still struggling how the WebappClassLoader.loadClass(String name, boolean resolve) be able to load the class ServletDef. Can you please give me some more insight into this method? I think the it should load the class via the catalina class loader as my previous assumption 1 was wrong. If this is the case, How does this method achieve that?
Many thanks,
Elgs
On Sep 25, 2012, at 9:28 PM, Mark Thomas <ma...@apache.org> wrote:
> On 25/09/2012 13:19, Elgs Chen wrote:
>> Dear Tomcat Developers,
>>
>> I have a question regarding the behavior of the WebClassLoader.loadClass(String name, boolean resolve) in the org.apache.catalina.loader package.
>>
>> I have the following assumptions, please correct me if any is wrong:
>> 1, It seems the WebClassLoader only uses the SystemClassLoader (or AppClassLoader) to loader tomcat core classes, like ServletDef;
>
> Wrong. See [1].
>
>> 2, It seems if tomcat is started up by the startup.sh from the bin directory, the classpath in the startup command line will include only the jars in the bin directory: bootstrap.jar, commons-daemon.jar and tomcat-juli.jar;
>
> Correct.
>
>> 3, ClassLoader.getSystemClassLoader() by default returns the class loader with the startup command-line classpath;
>
> Correct.
>
>> Now if the above three assumption are correct, it seems that it's not possible for the WebClassLoader to load the tomcat core classes as only the few bootstrap jars are in the system class loader's classpath. However, the fact is the startup.sh script indeed starts tomcat up. Why?
>
> The logical conclusion would be that one or more of the assumptions is
> wrong.
>
>
>> So my question is:
>> How does the startup.sh shipped with tomcat binary make the WebClassLoader to load the ServletDef?
>
> See [2], line 262.
>
> Mark
>
>
> [1] http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
> [2]
> http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Bootstrap.java?view=annotate
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: dev-help@tomcat.apache.org
>
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
Re: WebClassLoader using SystemClassLoader to load ServletDef?
Posted by Mark Thomas <ma...@apache.org>.
On 25/09/2012 13:19, Elgs Chen wrote:
> Dear Tomcat Developers,
>
> I have a question regarding the behavior of the WebClassLoader.loadClass(String name, boolean resolve) in the org.apache.catalina.loader package.
>
> I have the following assumptions, please correct me if any is wrong:
> 1, It seems the WebClassLoader only uses the SystemClassLoader (or AppClassLoader) to loader tomcat core classes, like ServletDef;
Wrong. See [1].
> 2, It seems if tomcat is started up by the startup.sh from the bin directory, the classpath in the startup command line will include only the jars in the bin directory: bootstrap.jar, commons-daemon.jar and tomcat-juli.jar;
Correct.
> 3, ClassLoader.getSystemClassLoader() by default returns the class loader with the startup command-line classpath;
Correct.
> Now if the above three assumption are correct, it seems that it's not possible for the WebClassLoader to load the tomcat core classes as only the few bootstrap jars are in the system class loader's classpath. However, the fact is the startup.sh script indeed starts tomcat up. Why?
The logical conclusion would be that one or more of the assumptions is
wrong.
> So my question is:
> How does the startup.sh shipped with tomcat binary make the WebClassLoader to load the ServletDef?
See [2], line 262.
Mark
[1] http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html
[2]
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Bootstrap.java?view=annotate
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org