Java, Classpath, Classloading = > Varias versiones del mismo jar / proyecto


Sé que esta puede ser una pregunta tonta para los codificadores experimentados. Pero tengo una biblioteca (un cliente http) que requieren algunos de los otros frameworks/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 classloader lo suficientemente inteligente como para separarlos de alguna manera? Lo más probable es que no? Cómo maneja esto el Classloader, en caso de que una Clase sea la misma en los tres frascos. ¿Cuál está cargado y por qué?

Hace el Classloader solo recoger exactamente uno tarro o mezcla clases arbitrariamente? Así, 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 todas al mismo jar?

¿Cómo se maneja este problema?

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

Author: Hardik Mishra, 2011-05-24

4 answers

Los problemas relacionados con Classloader son un asunto bastante complejo. En cualquier caso, debe tener en cuenta algunos hechos:

  • Los classloaders en una aplicación suelen ser más de uno. El cargador de clases bootstrap delega al 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á tratando de cargar, delega a su padre, y así sucesivamente, hasta que llegue al cargador de clases bootstrap. Si ninguno de ellos encuentran una referencia a la clase que está tratando de cargar se obtiene una ClassNotFoundException.

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

  • De acuerdo con la especificación del lenguaje java, no hay una restricción de unicidad para un nombre binario de clase, pero por lo que puedo ver, debe ser único para cada cargador de clase.

Puedo encontrar una manera de cargar dos clases con el mismo nombre binario, e implica que se carguen (y todas sus dependencias) por dos cargadores de clases diferentes que anulan 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é la personalización de classloader una tarea complicada. Prefiero sugerir evitar múltiples dependencias incompatibles si es posible.

 47
Author: Luca Putzu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-29 17:46:33

Cada classload elige exactamente una clase. Por lo general, el primero encontrado.

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

 19
Author: Tarlog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-24 08:15:17

Classloader cargará primero las clases del jar que se encuentren en el classpath. Normalmente, las versiones incompatibles de la biblioteca tendrán diferencias en los paquetes, Pero en caso poco probable que realmente incompatibles y no pueden ser reemplazados por uno-trate jarjar.

 6
Author: Alex Gitelman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-24 02:42:14

Los Classloaders cargan la clase bajo demanda. Esto significa que la clase requerida primero por su aplicación y bibliotecas relacionadas se cargará antes que otras clases; la solicitud para cargar las clases dependientes se emite normalmente durante el proceso de carga y enlace de una clase dependiente.

Es probable que encuentre LinkageErrors que indican que se han encontrado definiciones de clases duplicadas para los cargadores de clases normalmente no intentan determinar qué clase debe cargarse primero (si hay dos o más clases del mismo nombre presentes en la ruta de clases del cargador). A veces, el classloader cargará la primera clase que ocurre en el classpath e ignorará las clases duplicadas, pero esto depende de la implementación del loader.

La práctica recomendada para resolver este tipo de errores es utilizar un cargador de clases separado para cada conjunto de bibliotecas que tienen dependencias en conflicto. De esta manera, si un classloader intenta cargar clases desde una biblioteca, el dependiente las clases serían cargadas por el mismo classloader que no tiene acceso a las otras bibliotecas y dependencias.

 6
Author: Vineet Reynolds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-24 03:13:43