Est-il possible d'avoir des fichiers de la charge du système ClassLoader spécifié au moment de l'exécution?

StackOverflow https://stackoverflow.com/questions/1873916

Question

Je suis en train d'écrire un outil d'analyse statique pour une mission, il analyse bytecode Java en utilisant la bibliothèque ASM. L'une des parties de l'ASM que nous utilisons exige (ou du moins, semble exiger) que la classe soit chargé à partir du ClassLoader.

Nous espérions l'outil serait capable d'analyser les fichiers .class sans exiger le classpath. On charge déjà les .classes à partir d'un répertoire spécifié au moment de l'exécution et de les lire en utilisant un InputStream. Ceci est acceptable pour l'ASM dans la plupart des cas. Il y a certaines classes, comme SimpleVerifier, qui tentent de charger les classes bien.

Est-il possible, dans ce scénario, pour enregistrer les fichiers .class à charger afin que les appels à Class.forName() leur charge? Ou est-il un moyen facile d'étendre le ClassLoader pour permettre cela?


Edit: les informations sur URLClassLoader était utile. Malheureusement, l'utilisation Thread.currentThread().setContextClassLoader() à une instance de cela ne fonctionne pas dans ce scénario. Le code de la bibliothèque, je vous appelle en utilise un chargeur, il récupère l'initialisation d'instance à l'aide getClass().getClassLoader().

Au moment où je mets la URLClassLoader la classe n'a pas été initialisées donc je suppose que le contextClassLoader ne se charge pas cette classe.

Ai-je bien compris les réponses? Est-ce que l'aide de la URLClassLoader pour charger la classe de 3e partie soit une possibilité?

Était-ce utile?

La solution

Presque.

Si vous avez des classes compilées quelque part, vous pouvez les charger avec un URLClassLoader . Vous pouvez ensuite définir ce ClassLoader être le ClassLoader pour le thread courant: Thread.setContextClassLoader (ClassLoader)

Les utilisateurs peuvent obtenir que les fils contexte actuel chargeur de classe et l'utiliser pour accéder à la définition de la classe.

Autres conseils

Tout d'abord, l'ASM peut être utilisé de telle sorte qu'il ne sera pas utiliser ClassLoader pour obtenir des informations sur les classes.

Il y a plusieurs endroits dans le cadre de l'ASM où il charge les classes par défaut, mais tous ces endroits peuvent être redéfinie dans vos sous-classes. Sur le haut de ma tête:

  • ClassWriter.getCommonSuperClass () méthode est appelée uniquement lorsque l'indicateur de ClassWriter.COMPUTE_FRAMES est utilisé et peut être overwriten de ne pas utiliser ClassLoader pour obtenir inforamtion sur les classes. Vous pouvez trouver un exemple de cela dans ClassWriterComputeFramesTest qui introduit une abstraction ClassInfo
  • De la même méthode SimpleVerifier.getClass () est utilisée par SimpleVerifier.isAssignableFrom () et vous pouvez remplacer ce dernier et utiliser l'abstraction ClassInfo pour trouver la commune super type. Si je ne me trompe pas, le projet a mis en œuvre AspectWerkz chose semblable dans son code de correspondance de motif de type. Notez également qu'il ya SimpleVerifier.setClassLoader () méthode, vous pouvez utiliser si vous voulez continuer à charger vos propres classes.

Sur une note de côté, sur un JVMs de Sun, les classes chargées arrive à PermGen zone et ne peuvent pas être débarquées, il est donc pas une bonne idée de charger des classes uniquement à des fins d'analyse de code statique si vous pouvez éviter cela, surtout si outil serait intégré dans un processus long en direct, comme IDE.

Vous ne pouvez pas, pour autant que je sache, étendre le chargeur de classes du système lors de l'exécution, mais vous pouvez charger dynamiquement des classes à partir d'un emplacement arbitraire (pot ou répertoire) en utilisant URLClassLoader .

Vous pouvez essayer d'installer un « lanceur » dans le démarrage de votre application qui crée un URLClassLoader en lui passant les emplacements sur le chemin de classe et vos emplacements .class et commencer l'application de cette classloader.

Lorsque le SimpleVerifier est chargé par le URLClassLoader il sera également en mesure de charger les classes à partir des emplacements supplémentaires.

Oui, vous pouvez utiliser URLClassLoader

J'ai un test où je charge la classe lors de l'exécution. Cette classe est pas dans le chemin de classe (ni exister même lorsque le test est exécuté pour cette matière), puis il est chargé et fonctionne très bien.

Voici le code.

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

Tiré de cette question .

Je créé mon propre ClassLoader son tout à fait simple.

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top