web-dev-qa-db-fra.com

Java - comment charger différentes versions de la même classe?

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.

36
kms333

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();
43
helios

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.

7
AlexR

Pour un exemple d'implémentation de la réponse acceptée par @helios checkout github.com/atulsm/ElasticsearchClassLoader

0
Atul Soman

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

0
Andrey Borisov