Access multiple versions of a package in Java
We have several applications that use Apache HTTPClient 3 to make HTTP requests. Recently we have also began creating web service clients that use HTTPClient 4 for various reasons. The Apache stance is that "major releases are not backwards compatible". While I would love to update all of our projects to use version 4, that's simply not feasible.
So, while my main question is rathe开发者_如何学Cr general, my particular question is. How can I use HTTPClient version 3 and 4 in the same application? In our case an application can be a web, desktop, or command line app.
I have read the SO question for java-dynamically-load-multiple-versions-of-same-class which seems semi close but I don't care so much about the dynamic part. In fact I would like the JARs to be shipped with the app (example, WEB-INF/lib for web apps) I also see OSGi mentioned a lot in questions similar to this one but it seems to be overkill or perhaps overly complex (maybe a simple example could prove otherwise).
In the end I want to be able to hand a team a set of jars that they can drop in and it just works independent of their project using HTTP Client 3.
As others have stated, you can create multiple classloaders and load the two versions in isolation. This part is easy enough.
The problem is, this essentially splits your "class space", and it will still be very hard to refer to v3 from some parts of your application while referring to v4 from other parts of your application. You will have to partition your application very carefully... so why not just split it and deliver two applications?
OSGi could be a solution if you are able to factor out functionality into services. But converting a legacy application to OSGi is not something to take on lightly, and it will certainly not be a cheap escape from the trap that you have walked into. I say this as the author of a book on OSGi and a well-known OSGi evangelist. A long-term goal of converting your applications to OSGi would bring you great benefits, but will also involve significant up-front costs.
An easy but straightforward solution would be you get the sources for HttpClient3 and HttpClient4, and refactor the package names to something like
org.apache.commons.httpclient3 for HttpClient3 and org.apache.commons.httpclient4 for HttpClient4 to avoid collision. Then compile, package, done.
Now it is easy to switch between the two implementations and they don't collide in the classloader.
Use multiple class loaders, one for each HTTP Client you wish to embrace.
The simplest way is to extend URLClassLoader and hack it to hardcode the classpath for each version separately. Then you just need to make sure the rest of the code knows which version of the HTTP client to use (and accesses the correct classloader to get to it).
You have to use separate class loaders for v3 and v4. Put v3 and v4 jars to separate folders beyond your application classpath. Use URLClassLoadedr to load each one of the versions. The URL that you pass to each one of class loaders should contain URL to specific version of HTTP client.
But may I give you an advice? Check first that you really need all these before you are starting. That is right that the versions could be incompatible. But there is a huge chance that they are.
精彩评论