J'ai beaucoup lu sur Java classloaders, mais jusqu'à présent, je n'ai pas trouvé de réponse à cette question simple:
J'ai deux versions de com.abc.Hello.class dans des pots v1.jar et v2.jar. Je souhaite utiliser les deux dans mon application. Quelle est la manière la plus simple de procéder?
Je ne m'attends pas à être aussi simple, mais quelque chose dans ce sens serait génial:
Classloader myClassLoader = [magic that includes v1.jar and ignores v2.jar]
Hello hello = myclassLoader.load[com.abc.Hello]
Et dans une classe différente:
Classloader myClassLoader = [magic that includes v2.jar and ignores v1.jar]
Hello hello = myclassLoader.load[com.abc.Hello]
Je voudrais éviter d'utiliser OSGi.
Tu vas dans le bon sens. Vous devez tenir compte de certaines choses.
La chose normale est que les classes qui existent dans les chargeurs de classe parents sont utilisées. Donc, si vous voulez deux versions, ces classes ne doivent pas exister.
Mais si vous voulez interagir, vous pouvez utiliser la réflexion, ou mieux encore une interface commune. Je vais donc faire ceci:
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();
Vous avez presque écrit la solution. J'espère que le fragment de code suivant vous aidera.
ClassLoader cl = new URLClassLoader(new URL[] {new File("v1.jar").toURL()}, Thread.currentThread().getContextClassLoader());
Class<?> clazz = cl.loadClass("Hello");
Remplacer v1.jar
par v2.jar
et ce code chargera la version # 2.
Pour un exemple d'implémentation de la réponse acceptée par @helios checkout github.com/atulsm/ElasticsearchClassLoader
cela dépend de ce que vous allez faire avec les deux versions et comment, mais en général, vous pouvez au moins charger 2 versions de classe dans différents chargeurs de classe, puis définir le Thread.contextClassloader () et jouez ...
voir http://www.javaworld.com/javaqa/2003-06/01-qa-0606-load.html et http://docs.Oracle.com/javase/ jndi/tutorial/Beyond/misc/classloader.html