0

Ich versuche, Abhängigkeiten mit ASM 5.2 zu instrumentieren. Nachdem das JDK 1.8 beauftragt wurde, bin ich gezwungen, die COMPUTE_FRAMES-Option in meinem Klassenschreiber zu verwenden.ASM 5.2: Java.lang.linkage Fehler beim Instrumentieren von ApachHttpClient

Wenn Standard ClassWriter verwendet, kann es nicht bestimmte Klassen finden und wirft die folgende Ausnahme

java.lang.RuntimeException: java.lang.ClassNotFoundException: XXX 
    at org.objectweb.asm.ClassWriter.getCommonSuperClass(Unknown Source) 
    at org.objectweb.asm.ClassWriter.a(Unknown Source) 
    at org.objectweb.asm.Frame.a(Unknown Source) 
    at org.objectweb.asm.Frame.a(Unknown Source) 
    at org.objectweb.asm.MethodWriter.visitMaxs(Unknown Source) 
    ..... 

Um dieses Problem ich die getCommonSuperClass() -Methode des ClassWriter durch Erstellen einer benutzerdefinierten classWriter Klasse und übergeben Sie außer Kraft setzen zu lösen der Klassenlader von der transform(). Ich folgte die Beratung aus diesem Thread: ASM 5.0.3 With Java 1.8 incorrect maxStack with Java.lang.VerifyError: Operand stack overflow

Hier ist der CustomClassWriter Code:

class CustomClassWriter extends ClassWriter { 


    ClassLoader classLoader; 

    public CustomClassWriter(int writerFlag, ClassLoader loader) 
    { 
     super(writerFlag); 
     this.classLoader = loader; 
     System.out.println("Trace: Registering class loader from Code injector"); 
    } 

    /** 
    * This method returns common super class for both the classes. If no super class 
    * is present it returns java/lang/Object class. 
    * @param className1 
    * @param className2 
    * @return The String for the common super class of both the classes 
    */ 
    protected String getCommonSuperClass(String className1, String className2) 
    { 
     Class class1; 
     Class class2; 
     //System.out.println("Trace: Default Class loader :" + getClass().getClassLoader().toString()); 
     ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); 
     System.out.println("Trace: Context class loader is " + contextClassLoader.toString()); 
     System.out.println("Trace: Loaded class loaded :" + classLoader.toString()); 

     try 
     { 
      class1 = Class.forName(className1.replace('/', '.'), false, this.classLoader); 
      class2 = Class.forName(className2.replace('/', '.'), false, this.classLoader); 
      System.out.println("Trace: Class 1" + class1.toString()); 
      System.out.println("Trace: Class 2" + class2.toString()); 
     } 
     catch (Exception th) { 
      throw new RuntimeException(th.getMessage()); 
     } 

     if (class1.isAssignableFrom(class2)) { 
      return className1; 
     } 
     if (class2.isAssignableFrom(class1)) { 
      return className2; 
     } 

     if ((class1.isInterface()) || (class2.isInterface())) { 
      return "java/lang/Object"; 
     } 

     do { 
      class1 = class1.getSuperclass(); 
     } 
     while (!(class1.isAssignableFrom(class2))); 
     return class1.getName().replace('.', '/'); 
    } 


} 

Doch nach dies zu tun ich in weiered Problem laufen, wenn ich versuche, mit Eureka Netflix Bibliothek die Java-Agenten zu verwenden:

Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "org/apache/http/impl/client/AbstractHttpClient" 
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_144] 
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_144] 
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_144] 
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_144] 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_144] 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_144] 
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_144] 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_144] 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_144] 
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_144] 
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_144] 
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_144] 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_144] 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_144] 
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_144] 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_144] 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_144] 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_144] 
    at com.sun.jersey.client.apache4.ApacheHttpClient4.createDefaultClientHandler(ApacheHttpClient4.java:236) ~[jersey-apache-client4-1.19.1.jar:1.19.1] 
    at com.sun.jersey.client.apache4.ApacheHttpClient4.create(ApacheHttpClient4.java:181) ~[jersey-apache-client4-1.19.1.jar:1.19.1] 
    at com.netflix.discovery.shared.transport.jersey.EurekaJerseyClientImpl.<init>(EurekaJerseyClientImpl.java:52) ~[eureka-client-1.4.12.jar:1.4.12] 
    ... 58 common frames omitted 

Ich bin mir nicht sicher, was das genaue Problem hier ist. Wie unterscheidet sich der Klassenlader, erhält doppelte Definitionen. Was könnte der Weg sein, dies zu lösen? Jede Hilfe würde sehr geschätzt werden.

Edit: Zusätzlich zu den oben genannten Kontext packe ich bereits die HTTP-Client-Abhängigkeiten in benutzerdefinierten Namespace, so dass der Agent unsere eigenen Anrufe nicht instrumentieren.

Das Problem tritt genau auf, wenn ich versuche, Apache HTTP Client zu instrumentieren. Zur Zeit habe ich Instrumentierungen für Apache HTTP Client 4.2 und 4.3 und wenn ich die Anwendung boote, indem ich die Instrumentierung für 4.2 entferne, funktioniert alles gut.

Hier sind die Definitionen ich versuche zu Instrument:

private final static String HTTP_CLIENT_43_CLASS_NAME = "org/apache/http/impl/client/InternalHttpClient"; 
    private final static String HTTP_CLIENT_METHOD_43_NAME = "doExecute"; 
    private final static String HTTP_CLIENT_METHOD_43_SIGNATURE = "(Lorg/apache/http/HttpHost;Lorg/apache/http/HttpRequest;Lorg/apache/http/protocol/HttpContext;)Lorg/apache/http/client/methods/CloseableHttpResponse;"; 

    private final static String HTTP_CLIENT_42_CLASS_NAME = "org/apache/http/impl/client/AbstractHttpClient"; 
    private final static String HTTP_CLIENT_METHOD_42_NAME = "execute"; 
    private final static String HTTP_CLIENT_METHOD_42_SIGNATURE = "(Lorg/apache/http/HttpHost;Lorg/apache/http/HttpRequest;Lorg/apache/http/protocol/HttpContext;)Lorg/apache/http/HttpResponse;"; 
+1

Sie sind nicht gezwungen, 'COMPUTE_FRAMES' zu verwenden. Die viel bessere Option ist zu überlegen, welche Art von Instrumentierung Sie gerade machen und ob und auf welche Weise es die bereits existierenden Frames beeinflusst. – Holger

+0

@Holger können Sie mich bitte auf einige Ressourcen verweisen, um dies zu tun? Früher benutzte ich COMPUTE_MAX mit Sprungrahmen und den Code thew Ausnahmen von StackMapFrame erforderlich, wenn oracle jdbc Treiber instrumentiert wird. Mein Anwendungsfall ist hier, um die Start- und Stoppzeit zu berechnen, Ausnahmen aufzuzeichnen und die SQL-Zeichenfolge zu erfassen. Es gab eine andere Stapelüberlauf-Antwort von Ihnen Ich ging auf dem gleichen durch, war aber nicht sehr hilfreich –

+1

Zuerst sollten Sie die Optionen verstehen. Wenn Sie 'SKIP_FRAMES' verwenden, werden die ursprünglichen Frames nicht verarbeitet und daher nicht im instrumentierten Code angezeigt. Diese Option kann die Leistung verbessern, wenn Sie 'COMPUTE_FRAMES' verwenden, da Frames sowieso von Grund auf neu berechnet werden. Wenn Sie die Original-Frames beibehalten oder anpassen möchten, müssen Sie * SKIP_FRAMES nicht verwenden. Frames erscheinen dort, wo Zweige zusammengeführt werden. Wenn Sie die Zweige nicht ändern, sondern nur Code zwischen diesen Rahmen einfügen oder entfernen, passt ASM die Standorte bereits an. Sie müssen sie nur anpassen, wenn Sie Variablen usw. hinzufügen. – Holger

Antwort

1

Das Probelm ist, dass Sie Klassen bei der Instrumentierung durch die Verwendung ASM gemeinsamen Typ Resolver geladen werden. Auf diese Weise laden Sie die Klasse, die Sie gerade instrumentieren. Sobald Ihre Instrumentierung abgeschlossen ist, versucht die JVM, die Klasse zu definieren, aber wie zuvor definiert, ist dies nicht mehr möglich.

Aus diesem Grund sollten Sie das Laden von Klassen während der Instrumentierung vermeiden.

+0

Dieses Problem tritt speziell auf, wenn wir versuchen, den Apache-HTTP-Client zu instrumentieren.Als Update für den Thread packe ich bereits die Abhängigkeiten, die wir auf dem Apache-HTTP-Client haben, in den benutzerdefinierten Namespace, so dass der Agent nicht versucht, unseren eigenen Aufruf zu instrumentieren. In der Agent I Instrument 2 Versionen von Apache HTTP Client (4.2 und 4.3) und wenn ich die Instrumentierung von HTTP Client 4.2 entfernen funktioniert alles gut und die Anwendung startet mit Netflix Eureka-Bibliothek zu. Ich habe den Thread mit den Definitionen, die ich instrumentiere, aktualisiert –

+0

Dies liegt wahrscheinlich daran, dass die Bibliothek ein bestimmtes Muster in den Frame-Rahmen für instrumentierte Codes zeigt, die die anderen Bibliotheken nicht bereitstellen. –

+0

Ich sehe so haben Sie irgendwelche Vorschläge, wie ich vermeiden kann, class.forName() zu verwenden, um das doppelte Laden der Klasse zu verhindern, weil ich denke, dass das Problem davon stammt. Bitte lassen Sie mich wissen, wenn Sie Vorschläge haben. –

Verwandte Themen