2010-02-01 5 views
37

Non ho trovato una risposta chiara a questa domanda altrove, quindi proverò qui:Come trovare i barattoli e in quale ordine vengono caricati da un classloader?

C'è un modo (programmatico o altro) per ottenere un elenco di JAR/classi caricati da un Application Classloader nel preciso ordina che siano stati caricati? Per Application Classloader intendo il classloader che carica un'applicazione EAR in un server applicazioni (WLS, WAS, JBoss ...), ma ovviamente si applica a qualsiasi programma di caricamento classi.

Quindi, per generalizzare, quello che vorrei scoprire è l'elenco e l'ordine dei JAR caricati da un classloader specificato. Non singole classi, è abbastanza facile scoprirlo chiamando il classloader.getPackages(), ma un elenco di file JAR che sono stati caricati da questo classloader.

risposta

11

La risposta breve è no. I programmi di caricamento di classi non sono tenuti ad esporre la loro logica di ricerca.

Tuttavia, se l'istanza del classloader è URLClassLoader o una sottoclasse, è possibile accedere all'elenco di jar/directory, tramite il metodo getURLs(). Secondo il doc di questa classe, questi URL verranno ricercati in ordine.

In pratica, se stai cercando di scoprire da dove viene caricata una classe, la risposta di Steve è probabilmente più utile.

+2

Grazie, kdgregory. Questo è l'approccio che ho usato infine - in pratica ho scritto un'utilità che calcola la gerarchia del classloader in fase di esecuzione e interroga ogni classloader quale lista di risorse hanno caricato usando il metodo getURLs() se disponibile. Ha funzionato bene sia per WLS che per WAS. Nel caso di WLS, i propri programmi di caricamento classi non estendono URLClassloader, ma hanno un metodo diverso, getClassPath(), che restituisce un elenco ordinato di voci del percorso di classe. E tutti i classloader di WAS sembrano estendere l'URLClassloader, quindi getURLs() ha funzionato bene. Non l'ho ancora provato su JBoss. Marina – Marina

58

Hai provato a utilizzare l'opzione JVM -verbose:class. Visualizza tutti i file e le classi JAR caricati.

Esempio:

[Opened C:\Program Files\JDK160~1\jre\lib\rt.jar] 
[Loaded java.lang.Object from C:\Program Files\JDK160~1\jre\lib\rt.jar] 
+0

Grazie, Steve - sì, ho provato questa opzione e funziona benissimo se sei solo interessato a sapere quale classloader e da cosa .jar ha caricato una classe specifica. L'output diventa troppo travolgente, dato che la nostra applicazione ha migliaia di classi :). Ho usato un approccio simile a quello suggerito da kdgregory - vedi sotto. – Marina

0

Passare attraverso il dominio di protezione della classe (la combinazione posizione/certificato). per esempio. per PDFParser.class si ottiene in questo modo ...

PDFParser.class.getProtectionDomain().getCodeSource().getLocation().toString() 

Se viene caricato dalle classi JRE o da dirs omologati sarà un'eccezione cos queste classi di carico senza protezione ...

0

Come in alternativa, puoi utilizzare questo snippet di codice. Il risultato è un file composto da file jar correlati a un programma di caricamento classe e file di classe caricati dai programmi di caricamento classi di un oggetto (catena di programmi di caricamento classe inclusi i relativi genitori fino al programma di caricamento classe radice). I caricatori di classe sono separati dalle stelle.

Object obj = this; 
ClassLoader classLoader = obj.getClass().getClassLoader(); 
File file = new File("classlodersClassesJars.txt"); 
if(file.exists()) { 
    file.delete(); 
} 
if(classLoader != null) { // to escape from system classes that are loaded by bootstrap class-loader such as String. 
    do { 
     try { 
      Class clClass = classLoader.getClass(); 
      while(clClass != ClassLoader.class){ 
        clClass = clClass.getSuperclass(); 
      } 
      java.lang.reflect.Field domainField = clClass.getDeclaredField("domains"); 
      java.lang.reflect.Field classesField = clClass.getDeclaredField("classes"); 
      domainField.setAccessible(true); 
      classesField.setAccessible(true); 
      HashSet domains = (HashSet<String>) domainField.get(classLoader); 
      Vector classes = (Vector) classesField.get(classLoader); 
      FileOutputStream fos = new FileOutputStream("classlodersClassesJars.txt", true); 
      fos.write(("\n******************** " + classLoader.toString() + "\n").getBytes()); 
      fos.write(Arrays.toString(classes.toArray()).getBytes()); 
      Object[] reverseDomains = domains.toArray(); 
      org.apache.commons.lang.ArrayUtils.reverse(reverseDomains); 
      fos.write(Arrays.toString(reverseDomains).getBytes()); 
      fos.close(); 
      classLoader = classLoader.getParent(); 
     } catch (Exception exception) { 
      exception.printStackTrace(); 
      // TODO 
     } 
    } while (classLoader.getParent() != null); 
}