2012-01-03 20 views
11

Estoy usando JBoss 7 (la carga de dependencia se modificó en esta versión). Mi aplicación de guerra se carga a jar de servidor y necesita utilizar clases dentro de ellos, pero obtiene ClassNotFoundException. Así que no puedo encontrar una forma de agregar dependencias de tarje a módulos dinámicamente - MANIFEST.MF, jboss-deployment-structure.xml son formas estáticas de hacer esto.JBoss 7: cómo cargar dinámicamente jar

+1

Menciona que la carga de dependencia se modificó para JBoss 7. ¿Ha hecho esto usando versiones anteriores de JBoss? ¿Puedes describir tu enfoque anterior? – GargantuChet

+0

Supongo que [esta documentación] (https://community.jboss.org/wiki/ModuleCompatibleClassloadingGuide) puede ser útil – higuaro

Respuesta

5

Simplemente reformulando la pregunta para asegurarse de que sea correcta;

¿Desea poder subir un archivo jar arbitrario al servidor y luego usar las clases/recursos contenidos en la JVM? Sin reiniciar la JVM y/o editar su configuración, por supuesto.

Si ese es el caso, entonces debe cargar el contenedor en un cargador de clases (encadenando su cargador de clases actual si es necesario) y luego cargar la clase desde allí.

Suponiendo que almacena el fichero-jar físicamente en el servidor que podría, por ejemplo, hacer algo como:

public static Class<?> loadClass(String className, String jarFileLocation) 
     throws MalformedURLException, ClassNotFoundException { 
    URL jarUrl = new File(jarFileLocation).toURI().toURL(); 
    ClassLoader classLoader = new URLClassLoader(new URL[] {jarUrl }, MyClass.class.getClassLoader()); 
    return classLoader.loadClass(className); 
} 

public static Object executeMethodOndClass(String methodName, Class<?>[] parameterTypes, 
               Object[] parameters, String className, String jarFileLocation) 
     throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException, 
     NoSuchMethodException, InvocationTargetException { 
    Class<?> loadedClass = loadClass(className, jarFileLocation); 
    Method method = loadedClass.getMethod(methodName, parameterTypes); 
    Object instance = loadedClass.newInstance(); 
    return method.invoke(instance, parameters); 
} 

Sal. este es un código crudo, ni siquiera lo compilé ni lo puse a prueba; es debería funcionar, pero nada más que eso y existe la posibilidad de que haya pasado por alto algo o haya cometido un error tipográfico ;-)

Pps. Permitir que los archivos jar personalizados se carguen y las clases a partir de él se ejecuten trae consigo una serie de riesgos (de seguridad).

+0

Me gusta esta respuesta, pero no aborda la cuestión en su totalidad. La diferencia al final entre establecer una dependencia en jboss vía manfiest/jboss-deployment-structure.xml es que implícitamente hace que todas las clases de las que dependa estén disponibles en el cargador de clases de la aplicación, sin que sea necesario asignarles un nombre explícito o clasificarlas por separado. Esto tiene la ventaja de garantizar que cualquier sistema de Blackbox sobre el que se controle (envío a jsp handler, etc.) también tendrá acceso a esas clases (si se inician con el mismo cargador de clases de la aplicación). – Rhys

0

@Rage: This question en stackoverflow preguntado anteriormente podría darle algunas entradas sobre cómo organizar tarros: ya sean sus propias jarras o de terceros.

0

Prueba esto (he agarró algún lugar de Internet):

import java.io.File; 
import java.io.IOException; 
import java.lang.reflect.Method; 
import java.net.URL; 
import java.net.URLClassLoader; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 


public final class ClassPathHacker { 
    private static final Class<?>[] PARAMS = new Class<?>[] { URL.class }; 
    private static final Logger LOG_CPH = LoggerFactory.getLogger(ClassPathHacker.class); 

    private ClassPathHacker() {} 

    public static void addFile(final String pFileName) throws IOException { 
     final File myFile = new File(pFileName); 

     ClassPathHacker.addFile(myFile); 
    } 

    public static void addFile(final File pFile) throws IOException { 
     ClassPathHacker.addURL(pFile.toURI().toURL()); 
    } 

    public static void addURL(final URL pFileUrl) throws IOException { 

     /* variables definition */ 
     final URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
     final Class<?> sysClass = URLClassLoader.class; 

     try { 
      final Method myMethod = sysClass.getDeclaredMethod("addURL", PARAMS); 

      myMethod.setAccessible(true); 
      myMethod.invoke(sysLoader, new Object[] { pFileUrl }); 
     } catch (final Exception exc) { 
      ClassPathHacker.LOG_CPH.error(exc.getLocalizedMessage(), exc); 

      throw new IOException(exc.getLocalizedMessage()); 
     } 
    } 
} 

Junto con este método:

private static void hackClassPath(final File myData) { 
    if (myData.isDirectory()) { 

     /* block variables */ 
     final File[] myList = myData.listFiles(); 

     /* hacking classpath... */ 
     for (final File tmp : myList) { 
      try { 
       ClassPathHacker.addFile(tmp.getAbsolutePath()); 
       MainApplication.MAIN_LOG.trace("{} added to classpath", 
               tmp.getAbsolutePath()); 
      } catch (final IOException iOE) { 
       MainApplication.MAIN_LOG.error(iOE.getLocalizedMessage(), 
               iOE); 
      } 
     } 
    } 
} 

Y con este ejemplo de la llamada:

MainApplication.hackClassPath(new File("test/data")); 
    MainApplication.hackClassPath(new File("data")); 

Un poco raro, pero quizás funcione ... el tiempo de ejecución agrega todos los archivos JAr disponibles en los datos o el directorio de prueba/datos al cl asno

Cuestiones relacionadas