2010-12-14 8 views
5

Tenemos varias aplicaciones que utilizan Apache HTTPClient 3 para realizar solicitudes HTTP. Recientemente, también hemos comenzado a crear clientes de servicios web que utilizan HTTPClient 4 por varias razones. La postura de Apache es que "las principales versiones de no son compatibles con versiones anteriores". Si bien me gustaría actualizar todos nuestros proyectos para usar la versión 4, eso simplemente no es factible.Acceda a múltiples versiones de un paquete en Java

Entonces, aunque mi pregunta principal es bastante general, mi pregunta en particular es. ¿Cómo puedo usar HTTPClient versión 3 y 4 en la misma aplicación? En nuestro caso, una aplicación puede ser una aplicación web, de escritorio o de línea de comandos.

He leído el SO question for java-dynamically-load-multiple-versions-of-same-class que parece semi cerrado pero no me importa tanto la parte dinámica. De hecho, me gustaría que los JAR se envíen con la aplicación (por ejemplo, WEB-INF/lib para aplicaciones web). También veo OSGi mencionado mucho en preguntas similares a esta, pero parece ser excesivo o quizás demasiado complejo (tal vez un ejemplo simple podría demostrar lo contrario).

Al final quiero ser capaz de entregar un equipo de un grupo de botes que pueden pasar y simplemente funciona independiente de su proyecto utilizando HTTP Client 3.

+1

Este es un caso en el que la gobernanza arquitectónica hubiera sido una buena idea: tomar la decisión de mantener la versión 3 o mover todo a la versión 4. Ahora debe pagar los costos de implementación de una solución de mosaico, y solo empeorar con el tiempo – Anon

+1

@Anon: Sin ánimo de ofender pero sin conocer la situación, no aconsejaría hacer una declaración tan general. Dije "por varias razones" para rechazar tales comentarios. –

+0

OSGi al menos funciona (debe decidir si es exagerado o no), no conozco ninguna forma trivial de hacer esto aparte de tener dos servidores web, uno para cada versión de la biblioteca. –

Respuesta

5

Como han indicado otros, puede crear varios cargadores de clases y cargar las dos versiones de forma aislada. Esta parte es bastante fácil.

El problema es que esto esencialmente divide su "espacio de clase", y todavía será muy difícil referirse a v3 desde algunas partes de su aplicación al referirse a v4 de otras partes de su aplicación. Tendrá que particionar cuidadosamente su aplicación muy ... entonces ¿por qué no solo dividirla y entregar dos aplicaciones?

OSGi podría ser una solución si puede factorizar la funcionalidad en los servicios.Pero la conversión de una aplicación heredada a OSGi no es algo para tomar a la ligera, y ciertamente no será un escape barato de la trampa en la que has entrado. Lo digo como el autor de un libro sobre OSGi y un conocido evangelista de OSGi. Un objetivo a largo plazo de convertir sus aplicaciones a OSGi sería que le reportará grandes beneficios, pero también implicará importantes costos iniciales.

1

Use los cargadores de clases múltiples, uno para cada Cliente HTTP que desea adoptar.

La forma más simple es extender URLClassLoader y cortarlo para codificar el classpath para cada versión por separado. Entonces solo necesita asegurarse de que el resto del código sepa qué versión del cliente HTTP debe usar (y accede al cargador de clases correcto para acceder a él).

+0

¿Cómo funcionaría esto para una aplicación web en la que los JAR deben enviarse con los WAR? –

+0

Envíe todas las versiones de cada biblioteca a la que se hace referencia, pero colóquelas en otro lugar que no sea web-inf/lib. Su cargador de clases personalizado se ve en la ubicación "en otro lugar". Esto evita que el contenedor de guerra haga referencia a ellos directamente. –

1

Tienes que usar cargadores de clases separados para v3 y v4. Coloque los archivos jar v3 y v4 en carpetas separadas más allá de la classpath de su aplicación. Use URLClassLoadedr para cargar cada una de las versiones. La URL que pase a cada uno de los cargadores de clases debe contener una URL para una versión específica del cliente HTTP.

¿Pero puedo darte un consejo? Verifique primero que realmente necesita todo esto antes de comenzar. Es correcto que las versiones podrían ser incompatibles. Pero hay una gran posibilidad de que lo sean.

+1

Creo que te refieres a "grandes posibilidades de que * no *" Sé que HTTP Client v3 y V4 no funcionan bien juntos. –

2

Una solución fácil, pero sencilla sería obtener las fuentes de HttpClient3 y HttpClient4 y refactorizar los nombres de los paquetes a algo así como

org.apache.commons.httpclient3 para HttpClient3 y org.apache.commons .httpclient4 para HttpClient4 para evitar colisiones. Luego compila, empaca, listo.

Ahora es fácil cambiar entre las dos implementaciones y no colisionan en el cargador de clases.

+1

Si bien esto funciona para un solo contenedor, crea más problemas de los que resuelve. Es posible que necesite apache.commons.logging, por ejemplo, y ambas versiones dependerán de las diferentes versiones del registro de commons (ya que se lanzaron en diferentes momentos). Ahora puede volver a empaquetar el registro de commons de la manera anterior, pero luego debe volver atrás y editar manualmente todo el código fuente en los clientes http reempaquetados para hacer una referencia correcta. Pronto, esa solución se convierte en un gran desastre. –

+1

¿Dependen realmente de las diferentes versiones de la tala común? El último debería funcionar bien con ambos, ¿no? – Thilo

+2

Tenga en cuenta que las personas de commons-lang van por esta ruta. Commons Lang 3 usará el nombre del paquete org.apache.commons.lang3. Si vas a tener cambios API incompatibles, un nuevo nombre de paquete probablemente no sea la peor idea. – Thilo

Cuestiones relacionadas