Java, Classpath, Classloading => Múltiples versiones del mismo jar/proyecto

Resuelto jens asked hace 13 años • 5 respuestas

Sé que esta puede ser una pregunta tonta para programadores experimentados. Pero tengo una biblioteca (un cliente http) que requieren algunos de los otros marcos/jars utilizados en mi proyecto. Pero todos ellos requieren diferentes versiones principales como:

httpclient-v1.jar => Required by cralwer.jar
httpclient-v2.jar => Required by restapi.jar
httpclient-v3.jar => required by foobar.jar

¿Es el cargador de clases lo suficientemente inteligente como para separarlos de alguna manera? ¿Probablemente no? ¿Cómo maneja esto el cargador de clases, en caso de que una clase sea la misma en los tres archivos jar? ¿Cuál está cargado y por qué?

¿El Classloader solo recoge exactamente un frasco o mezcla clases arbitrariamente? Entonces, por ejemplo, si una clase se carga desde la Versión-1.jar, ¿todas las demás clases cargadas desde el mismo cargador de clases irán al mismo contenedor?

¿Cómo manejas este problema?

¿Existe algún truco para "incorporar" de alguna manera los frascos en el "required.jar" de modo que sean vistos como "una unidad/paquete" por el Classloader, o vinculados de alguna manera?

jens avatar May 24 '11 09:05 jens
Aceptado

Los problemas relacionados con el cargador de clases son un asunto bastante complejo. En cualquier caso debes tener en cuenta algunos datos:

  • Los cargadores de clases en una aplicación suelen ser más de uno. El cargador de clases bootstrap delega al usuario apropiado. Cuando crea una instancia de una nueva clase, se invoca el cargador de clases más específico. Si no encuentra una referencia a la clase que está intentando cargar, la delega a su padre, y así sucesivamente, hasta llegar al cargador de clases de arranque. Si ninguno de ellos encuentra una referencia a la clase que está intentando cargar, obtendrá una ClassNotFoundException.

  • Si tiene dos clases con el mismo nombre binario, que el mismo cargador de clases puede buscar, y desea saber cuál de ellas está cargando, solo puede inspeccionar la forma en que ese cargador de clases específico intenta resolver un nombre de clase.

  • Según la especificación del lenguaje Java, no existe una restricción de unicidad para el nombre binario de una clase, pero hasta donde puedo ver, debería ser único para cada cargador de clases.

Puedo encontrar una manera de cargar dos clases con el mismo nombre binario, e implica cargarlas (y todas sus dependencias) mediante dos cargadores de clases diferentes que anulen el comportamiento predeterminado. Un ejemplo aproximado:

    ClassLoader loaderA = new MyClassLoader(libPathOne);
    ClassLoader loaderB = new MyClassLoader(libPathTwo);
    Object1 obj1 = loaderA.loadClass("first.class.binary.name", true)
    Object2 obj2 = loaderB.loadClass("second.class.binary.name", true);

Siempre encontré que la personalización del cargador de clases era una tarea complicada. Prefiero sugerir evitar múltiples dependencias incompatibles si es posible.

Luca Putzu avatar May 24 '2011 09:05 Luca Putzu

Cada carga de clases elige exactamente una clase. Generalmente es el primero que se encuentra.

OSGi tiene como objetivo resolver el problema de múltiples versiones del mismo jar. Equinox y Apache Felix son las implementaciones comunes de código abierto para OSGi.

Tarlog avatar May 24 '2011 08:05 Tarlog

Classloader cargará primero las clases del jar que se encontraba en el classpath. Normalmente, las versiones incompatibles de la biblioteca tendrán diferencias en los paquetes, pero en un caso poco probable, son realmente incompatibles y no se pueden reemplazar por uno: pruebe con jarjar.

Alex Gitelman avatar May 24 '2011 02:05 Alex Gitelman