2010-03-10 12 views
11

En un servidor Tomcat 5.5, puse una clase en classpath del sistema (y modifico catalina.bat para elegirlo), o si puse class en el directorio lib compartido. Ahora si tengo dos aplicaciones diferentes que usan la misma clase que no tienen la clase en sus directorios lib/classes de WEB-INF, usan la misma instancia de la clase. Entiendo el concepto de que un cargador de clases delegará en su cargador de clases padre para encontrar una clase si no puede encontrarla, por lo que en este caso, dado que la clase no está presente en las clases WEB-INF/o WEB-INF/lib, El cargador de clases de WebAppX probará el cargador de clases compartido, común y del sistema, respectivamente.Comportamiento del cargador de clases en Tomcat con múltiples aplicaciones

Sin embargo, esto de alguna manera me parece extraño que dos aplicaciones diferentes puedan compartir un contexto utilizando este método. ¿Alguien podría ayudarme a entender por qué esto es así? p.ej. en el código siguiente, los dos servlets se despliegan en guerras separadas mientras se comparte CommonCounter, y pueden leer los valores del contador incrementados por el otro.

Editar Parece contrario a la intuición para mí que dos aplicaciones separadas pueden compartir un contexto de esta manera. De hecho, si tienen la misma instancia de la clase, pueden incluso implementar multiprocesamiento/sincronización en dos aplicaciones diferentes, lo que parece extremadamente contrario a la intuición.

package com.test; 
public class CommonCounter { 

    public static int servlet1; 
    public static int servlet2; 
} 




public class Servlet1 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet { 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     CommonCounter.servlet1++; 
     System.out.println("Other one had "+CommonCounter.servlet2+" hits"); 
    } 
} 



public class Servlet2 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet { 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     CommonCounter.servlet2++; 
     System.out.println("Other one had "+CommonCounter.servlet1+" hits"); 
    } 
} 
+1

No entiendo la pregunta: usted explica que las clases en el cargador de clases del sistema de Tomcat se comparten entre todas las aplicaciones. Por lo tanto, ambas aplicaciones acceden a la misma clase y, por lo tanto, leen de los mismos campos estáticos y pueden ver el efecto de cada uno. –

+0

Sí, pero me parece contradictorio que dos aplicaciones separadas puedan compartir un contexto de esta manera. De hecho, si tienen la misma instancia de la clase, pueden incluso implementar multiprocesamiento/sincronización en dos aplicaciones diferentes, lo que parece extremadamente contrario a la intuición. – saugata

Respuesta

10

Como dicen los comentarios, que he explicado correctamente por qué se observa el comportamiento que se observa.

La clave es cómo se estructuran los ClassLoaders. Es completamente posible que dos ClassLoaders dentro de una JVM carguen cada clase y, por lo tanto, contengan copias separadas e independientes de los campos estáticos. "estático" convierte algo "global" en un Cargador de clases, no en una JVM. Tomcat, supongo, no podría contener un ClassLoader a nivel de contenedor con bibliotecas compartidas, y de alguna manera obligaría a cada aplicación ClassLoader a cargar bibliotecas compartidas por separado.

Pero eso sería un desperdicio para otras clases comunes como las API J2EE y la implementación. Y, en principio, las clases no deberían depender de esta estructura de ClassLoader de todos modos.

Es por eso que no debe poner dependencias de aplicaciones en las carpetas de bibliotecas compartidas de Tomcat. Esa es la 'solución'. Vincula su aplicación a la configuración e implementación específicas del contenedor, lo que va en contra del principio de las aplicaciones web J2EE. Simplemente ponga copias de las dependencias en WEB-INF/lib para cada aplicación.

El comportamiento que observa es otra razón para no hacer esto: las aplicaciones se vuelven menos aisladas entre sí. No me parece una conducta contraintuitiva, pero supongo que es solo porque estoy acostumbrado a cómo funciona y piensa Tomcat sobre estas cosas.

+0

Tengo un problema similar cuando necesito compartir objetos entre dos aplicaciones web. Me parece que poner el objeto en el cargador de clases del sistema es probablemente la única solución. Ver http://stackoverflow.com/questions/9453109/using-jndi-to-share-servlet-session-objects-and-data-in-tomcat – ziggy

+1

Tal vez ... pero compartir con webapps definitivamente no es algo que destinado a hacer así. (Sin embargo, mire los archivos .ear) Puede suceder que funcione, pero no se garantiza que funcione, por las razones anteriores. –

Cuestiones relacionadas