Strange Spring behavior on Jetty when spring.jar is in WEB-INF/lib/ instead of classpath
I'm running Eclipse with the run-jetty-run plugin to launch my J2EE web apps. My project uses Spring, and the spring configuration uses things like HttpInvokerProxy and propertie开发者_如何学编程s placeholder.
- When the spring jars are on the classpath (I mean configured in the "classpath" tab of the "run configuration") and external (not in WEB-INF/lib), everything works fine.
- But when I place spring.jar (or all spring jars) in the WEB-INF/lib/ directory (+referenced in the classpath), the trouble starts. I tried with both values of Jetty's parentLoaderPriority:
- when parentLoaderPriority is
true
, I get a complaint of Xerces saying it can't validate the spring.xml's XSD (so I guess Jetty's embedded different version of xerces conflicting with mine) - when parentLoaderPriority is
false
, the property placeholder doesn't work anymore and (I tried replacing with the direct values) Spring also fails to convert the HttpInvokerProxy into the correct interface, like some classes are missing
- when parentLoaderPriority is
- Finally, when I leave all my jars in WEB-INF/lib and remove the matching classpath entries, it can't find the classes: I get a ClassDefNotFoundException com/google/common/collect/Lists although google-collections.jar is in WEB-INF/lib and contains the class file... This with both values of parentLoaderPriority.
Method #3 works fine in Tomcat, though. So I guess this jetty launcher has some classloading configuration I'm doing wrong ?
It sounds like your application is using something on the 'external' classpath (I'll call it X) and passing it a reference; this works just fine because 'external' is in a parent classloader to your application.
'X' then uses the reference to do something with spring. However, spring is on your app's classpath, but X is on the external classpath. Spring is therefore not visible to X, hence the error.
As you discovered, putting spring into the external classpath is a valid workaround. This should also work if spring is in both the external and web-app classpaths.
As to what 'X' is? The most likely candidate would be commons-logging, which has a long history of screwing around with classloaders. You might want to consider using an slf4j implementation instead (like Logback) and provide the commons-logging interface via jcl-over-slf4j
Resources:
- http://articles.qos.ch/classloader.html
- http://day-to-day-stuff.blogspot.com/2007/10/announcement-version-99-does-not-exist.html
- http://www.slf4j.org/manual.html
- http://logback.qos.ch/
精彩评论