2010-11-09 10 views
25

Tengo varias aplicaciones web ejecutándose en un servidor de aplicaciones y cada archivo WAR de la aplicación web contiene una copia del mismo archivo jar.¿Cómo funciona la carga de clases cuando existe la misma clase en diferentes aplicaciones en el mismo servidor?

¿Esto significa que una clase en ese archivo jar se cargará varias veces en la JVM, una vez por cada archivo WAR en que exista? A continuación, si tengo un método estático sincronizado en dicha clase, solo está sincronizado entre hilos dentro de la aplicación web, existe pero no está sincronizado con el mismo método en la misma clase en un archivo jar diferente en un archivo diferente. ¿Archivo WAR? (Espero que la pregunta tenga sentido, aclarará si es necesario).

Si este es el caso supongo que la mejor solución es eliminar el archivo jar de cada archivo WAR y desplegarlo en una carpeta classpath compartida en el servidor?

Respuesta

29

Un cargador de clases Java normalmente funciona buscando clases en uno o más lugares en una secuencia fija. Por ejemplo, el cargador de clases que carga su aplicación cuando lo ejecuta desde la línea de comando se ve primero en el archivo rt.jar (y otros en el bootclasspath), y luego en los directorios y archivos JAR especificados por su classpath.

Una carga de clase de webapp es similar en principio, pero un poco más complicada en la práctica. Para una aplicación web particular, el cargador de clases de una aplicación busca clases en el siguiente orden. Por ejemplo Tomcat 6 busque las clases en este orden:

  1. clases de archivos de inicio de la JVM
  2. clases de cargador de clases del sistema (descritos here)
  3. /WEB-INF/classes de la aplicación web
  4. /WEB INF/lib/*. jar de la aplicación web
  5. $ CATALINA_HOME/lib
  6. $ CATALINA_HOME/lib/*. jar

Por supuesto, una vez que el cargador de clases ha encontrado la clase que busca, no busca más. Por lo tanto, las clases con el mismo nombre más adelante en el pedido no se cargarán.

La complicación es que el contenedor web tiene un cargador de clases para cada aplicación web, y estos cargadores de clases delegan a otros cargadores de clases que administran las clases comunes. En la práctica, esto significa que algunas clases solo se cargarán una vez para todo el contenedor (por ejemplo, 1. y 2.) y otras pueden ser cargadas varias veces por diferentes cargadores de clases.

(Cuando una clase se carga más de una vez, da como resultado distintos objetos Class y estáticas de clase distintas. Las versiones de la clase son diferentes en cuanto a la JVM y no puede encasillar de una versión a otra .)

Finalmente, Tomcat se puede configurar para permitir que las webapps individuales se "carguen en caliente". Esto implica detener una aplicación web, crear un nuevo cargador de clases y reiniciarla.

FOLLOWUP

Así que ... la sincronización de un método estático no protegerá el acceso a un recurso compartido en el que la clase se ha cargado varias veces?

Depende de los detalles, pero probablemente no sea así. (O para mirar si de otra manera, si una clase tiene realidad ha cargado varias veces, a continuación, un método de cada "carga" de la clase static accederá a un conjunto diferente de static campos.)

Si realmente quiere que una instancia de clase de aplicación singleton sea compartida por varias aplicaciones web en el mismo contenedor, es más simple si coloca la clase en $CATALINA_HOME/lib o su equivalente. Pero también debe preguntarse si este es un buen diseño del sistema. Considere combinar webapps, o usar el reenvío de solicitudes, etc., en lugar de una estructura de datos compartida. El patrón singleton tiende a ser problemático en webapps, y este sabor es aún más.

+0

Gracias por la respuesta. Sí, me encontré con el problema del casting previamente ahora que lo mencionas. Entonces, para responder a mi pregunta, ¿sincronizar un método estático no protegerá el acceso a un recurso compartido donde la clase se ha cargado varias veces? – CodeClimber

+0

@Stephane C Mientras trabajaba en varias aplicaciones web desplegadas en Tomcat, obtuve una excepción vinculada (recurso ya cargado en el cargador de clases diferente). Lo resolví moviendo el recurso a TC/bin dir para que TC Cloader lo cargue y se resolvió el problema. ¿Sabes por qué estaba recibiendo ese error? ¿Por qué el mismo recurso no puede ser cargado por 2 cargadores de clases diferentes de 2 diferentes aplicaciones web? – bluelurker

+0

En esta respuesta, se puede leer que diferentes cargadores de clase WAR causan diferentes versiones de clase para la "misma" clase, i. mi. al cargar una clase 'A' de e. gramo. un JAR 'a.jar' en' WEB-INF/lib' que se distribuye como el mismo archivo exacto en diferentes WAR en el mismo servidor (o EAR). Cuando quiero construir un caché que abarque todos los WAR en el servidor (o en el EAR) de las instancias de la clase 'A', esto no funcionará (excepto que muevo JAR' a.jar' a '~/lib/ext' o más) Will 'serialVersionUID' rescatar mi caché en este punto? –

0

La mayoría del uso del servidor de aplicaciones más específico a lo largo de una ruta tiene prioridad política. Si tiene varias bibliotecas que hacen lo mismo, debe considerar colocarlas en el servidor de aplicaciones lib (fe: INICIO_TOMACA/lib)

4

Los servidores de aplicaciones Java EE suelen utilizar varios cargadores de clases para aislar aplicaciones entre sí, y permiten nuevas versiones de una aplicación para implementar sin afectar otras aplicaciones.

Obtiene patrones como varios archivos WAR y un archivo EJB en un EAR con una jerarquía de cargadores de clases, cada WAR tiene su propio.

Esto lleva a la duplicación como usted describe, pero esto no es necesariamente algo malo. Significa que incluso puede tener diferentes versiones de los mismos JAR desplegados al mismo tiempo, y que en realidad pueden ser beneficiosos, lo que permite la migración incremental a nuevas versiones.

Algunos servidores de aplicaciones (WebSphere para exmaple) tienen soporte explícito para un concepto de biblioteca compartida, y yo uso eso.

Tenga cuidado de simplemente colocar JAR en classpaths arbitrarios, se corre el riesgo de desestabilizar el servidor de la aplicación.

+0

Tomcat también admite bibliotecas compartidas ... en $ CATALINA_HOME/lib –

+0

En cuanto a JBoss: admite "repositorios de clase". Puede configurar JBoss para ver las clases de otros WAR. Pero esto solo causa problemas, como pérdidas de memoria y errores de espacio PermGen, cuando algún WAR se despliega incorrectamente. – iirekm

Cuestiones relacionadas