Java - как загрузить разные версии одного и того же класса?
Я много читал о загрузчиках классов Java, но до сих пор не смог найти ответ на этот простой вопрос:
У меня есть две версии com.abc.Hello.class в jars v1.jar и v2.jar. Я хочу использовать оба в моем приложении. Какой самый простой способ сделать это?
Я не ожидаю, что все будет так просто, но что-то в этом роде было бы здорово:
Classloader myClassLoader = [magic that includes v1.jar and ignores v2.jar]
Hello hello = myclassLoader.load[com.abc.Hello]
И в другом классе:
Classloader myClassLoader = [magic that includes v2.jar and ignores v1.jar]
Hello hello = myclassLoader.load[com.abc.Hello]
Я хотел бы избежать использования OSGi.
4 ответа
Вы идете правильным путем. Вы должны принять во внимание некоторые вещи.
Обычно используются классы, которые существуют в родительских загрузчиках классов. Поэтому, если вы хотите две версии, эти классы не должны быть там.
Но если вы хотите взаимодействовать, вы можете использовать рефлексию или, что еще лучше, общий интерфейс. Итак, я сделаю это:
common.jar:
BaseInterface
v1.jar:
SomeImplementation implements BaseInterface
v2.jar:
OtherImplementation implements BaseInterface
command-line:
java -classpath common.jar YourMainClass
// you don't put v1 nor v2 into the parent classloader classpath
Then in your program:
loader1 = new URLClassLoader(new URL[] {new File("v1.jar").toURL()}, Thread.currentThread().getContextClassLoader());
loader2 = new URLClassLoader(new URL[] {new File("v2.jar").toURL()}, Thread.currentThread().getContextClassLoader());
Class<?> c1 = loader1.loadClass("com.abc.Hello");
Class<?> c2 = loader2.loadClass("com.abc.Hello");
BaseInterface i1 = (BaseInterface) c1.newInstance();
BaseInterface i2 = (BaseInterface) c2.newInstance();
Вы почти написали решение. Я надеюсь, что следующий фрагмент кода поможет.
ClassLoader cl = new URLClassLoader(new URL[] {new File("v1.jar").toURL()}, Thread.currentThread().getContextClassLoader());
Class<?> clazz = cl.loadClass("Hello");
замещать v1.jar
от v2.jar
и этот код загрузит версию #2.
Для примера реализации принятого ответа от @helios checkout http://github.com/atulsm/ElasticsearchClassLoader
Это зависит от того, что вы собираетесь делать с обеими версиями и как, но в целом вы можете по крайней мере загрузить 2 версии класса в разные загрузчики классов, а затем установить Thread.contextClassloader() и играть...
см. http://www.javaworld.com/javaqa/2003-06/01-qa-0606-load.html и http://docs.oracle.com/javase/jndi/tutorial/beyond/misc/classloader.html