0

ASM 5.2를 사용하여 계측기 계측을 시도하고 있습니다. JDK 1.8이 위임 된 상태에서 필자는 클래스 작성기에서 COMPUTE_FRAMES 옵션을 사용해야합니다. 기본 ClassWriter를 사용하는 경우ASM 5.2 : ApachHttpClient를 계측 할 때 Java.lang.linkage 오류

는 특정 클래스를 찾아 다음과 같은 예외 내가 정의 classWriter 클래스를 생성하고 전달하여 ClassWriter의 getCommonSuperClass() 메소드를 오버라이드 (override)이 문제를 해결하기 위해

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) 
    ..... 

에게 던졌습니다 수 없습니다 transform()의 클래스 로더 내가 유레카 넷플릭스 라이브러리와 자바 에이전트를 사용하려고하면

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('.', '/'); 
    } 


} 

그러나,이 일 후에 내가 weiered 문제로 실행 : 여기 ASM 5.0.3 With Java 1.8 incorrect maxStack with Java.lang.VerifyError: Operand stack overflow

가 CustomClassWriter 코드 :이 스레드에서 조언을 따랐다 :

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 

정확한 문제는 무엇입니까? 클래스 로더가 어떻게 다르게되면 중복 된 정의가 생깁니다. 이 문제를 해결할 수있는 방법은 무엇일까요? 어떤 도움이라도 대단히 감사하겠습니다.

편집 : 위의 컨텍스트 외에도 에이전트가 자체 호출을 계측하지 않도록 http 클라이언트 종속성을 사용자 지정 네임 스페이스에 다시 패키지하고 있습니다.

Apache HTTP 클라이언트를 인스트루먼트하려고하면 문제가 발생합니다. 현재 Apache HTTP Client 4.2 및 4.3에 대한 도구가 있으며 4.2 용 계측을 제거하여 응용 프로그램을 부팅하면 모든 것이 잘 작동합니다.

여기에 내가 악기를 시도하고있는 정의입니다 :

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

'COMPUTE_FRAMES'을 사용하지 않아도됩니다. 훨씬 더 좋은 옵션은 현재 수행중인 Instrumentation의 종류와 기존 프레임에 어떤 방식으로 영향을 주는지 여부를 고려하는 것입니다. – Holger

+0

@Holger이 작업을 수행하는 데 필요한 리소스를 알려주십시오. 이전에 필자는 oracle jdbc 드라이버를 인스트루먼트 할 때 StackMapFrame의 예외를 제외하고 코드 건너 뛰기 프레임과 함께 COMPUTE_MAX를 사용했습니다. 여기에 사용 사례는 시작 및 중지 시간을 계산하고 예외를 기록하며 SQL 문자열을 캡처하는 것입니다. 다른 스택 오버플로가 있었지만 동일한 결과를 얻었지만 많은 도움이되지는 않았습니다. –

+1

먼저 옵션을 이해해야합니다. 'SKIP_FRAMES'을 사용하면 원본 프레임이 처리되지 않으므로 인스트루먼트 된 코드에 나타나지 않습니다. 이 옵션은 프레임을 처음부터 다시 계산하므로'COMPUTE_FRAMES'를 사용할 때 성능을 향상시킬 수 있습니다. 원래 프레임을 유지하거나 조정하려면 * SKIP_FRAMES을 사용하면 안됩니다. 분기가 병합되는 지점에 프레임이 나타납니다. 분기를 수정하지 않고이 프레임들 사이에 코드를 삽입하거나 제거 할 때 ASM은 이미 위치를 수정합니다. 변수를 추가 할 때만 변수를 적용하면됩니다. – Holger

답변

1

probelm 당신이 ASM의 일반적인 유형 해결 프로그램을 사용하여 계측 중에 클래스를로드하는 것입니다. 이렇게하면 현재 계측중인 클래스를로드하고 있습니다. 인스 트루먼 테이션이 완료되면 JVM은 클래스를 정의하려고하지만 이전에 정의 된대로 더 이상 가능하지 않습니다.

계측 중에는 클래스를로드하지 마십시오.

+0

이 문제는 특별히 apache http 클라이언트를 계측하려고 할 때 발생합니다.스레드에 대한 업데이트로 에이전트가 자체 호출을 계측하지 않도록 아파치 http 클라이언트에서 사용자 지정 네임 스페이스에 대한 종속성을 이미 다시 패키징하고 있습니다. 에이전트에서 Apache HTTP 클라이언트 (4.2 및 4.3)의 2 버전을 계측하고 HTTP 클라이언트 4.2의 계측을 제거하면 모든 것이 잘 작동하고 응용 프로그램도 Netflix 유레카 라이브러리로 부팅됩니다. 내가 계측중인 정의로 스레드를 업데이트했습니다. –

+0

이것은 라이브러리가 다른 라이브러리에 노출되지 않은 계장 코드 스택 프레임의 특정 패턴을 표시하고 있기 때문일 수 있습니다. –

+0

클래스의 중복로드를 막기 위해 class.forName()을 사용하지 않도록하는 방법에 대한 제안이 있으니 참조하시기 바랍니다. 제안 사항이 있으면 알려주십시오. –