2012-03-01 4 views
8

일부 Java 바이트 코드 수정을 수행하기 위해 asm 라이브러리를 사용하고 있습니다. 특히 새로운 클래스와 메소드를 구현하기 위해 클래스를 수정해야합니다. 현재 나의 접근 방식은 javaagent를 통해 코어 asm API를 사용하고있다. 정적 인 .class 파일을 수정하는 것과는 반대로이 동적 인 접근 방식을 유지하고 싶습니다.Asm 코드 내에서 Instrumentation.retransformClasses()를 올바르게 사용하려면 어떻게해야합니까?

더 높은 수준에서 내 문제는 B에서 확장되는 A 클래스를 수정하는 경우 B도 수정해야한다는 것입니다. (클래스가 JVM에서로드되는 방식에 대한 내 이해를 감안할 때 클래스 B는 항상 클래스 A가되기 전에 변압기에 건네 질 것입니다. (내가 틀렸다면 수정하십시오.) 그 가정을 감안할 때, 저는 다시 돌아 가야한다고 생각합니다. B. 내 접근 방식은 다음과 같습니다. 코드의 비트 :

public byte[] transform(ClassLoader l, String name, Class<?> clazz, ProtectionDomain d, byte[] b) { 
     throws IllegalClassFormatException { 
    // **1** 
    System.out.println("--->>> " + name); 

    if (interestingClass(name)) { 
     try { 
      ClassReader cr = new ClassReader(b); 
      ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); 
      PyClassVisitorAdapter pv = new PyClassVisitorAdapter(cw, name); 
      cr.accept(pv, 0); 

      // **2** Retrieve the superclass and try to transform that 
      if (! "Ljava/lang/Object;".equals(pv.getSuperName())) { 
       String cName = classJvmToCanonical(pv.getSuperName()); 
       Class[] classes = inst.getAllLoadedClasses(); 
       for (Class c : classes) { 
        if (c.getName().equals(cName)) { 
         inst.retransformClasses(c); 
         break; 
        } 
       } 
      } 

      // Dump the transformed class 
      ClassReader cr2 = new ClassReader(cw.toByteArray()); 
      ClassWriter cw2 = new ClassWriter(cr2, 0); 
      TraceClassVisitor tcv = new TraceClassVisitor(cw2, new PrintWriter(System.out)); 
      cr2.accept(tcv, 0); 

      return cw2.toByteArray(); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
      return null; 
     } 
    } else { 
     return b; 
    } 
} 

( inst 생성자에 전달됩니다 Instrumentation에 대한 핸들입니다)

내가 힘들게 지내고있는 부분은 **2**의 설명에 표시된 블록입니다. 다시 A가 B를 확장한다고 가정 해 봅시다. A 변환에 '관심이 있습니다'라고 말하자. 내가 기대하는 것은 **1**에 수퍼 클래스 (B)의 이름이 인쇄되는 것을 볼 수있다. 첫 번째 단계에서 재미 있다고 생각하면) **2**에 도착하면 A의 수퍼 클래스가 B라는 것을 알게되면 B를 다시 변환해야합니다.이 시점에서이 메서드가 다시 호출 될 것으로 기대하고 있습니다 (inst.retransformClasses() 통해). 나는 B가 **1**에 인쇄되는 것을 볼 것입니다. 그러나 나는 그렇지 않습니다. (print 문을 추가하고 retransform 호출에 도달했는지 확인합니다. 또한 Instrumentation.isRetransformClassesSupported()Instrumentation.isModifiableClass(c)이 모두 true를 반환하는지 확인했습니다).

저는 에이전트를 올바르게 설정했다고 생각합니다. 매니페스트에서 Can-Retransform-Classes 및 Can-Redefine-Classes를 모두 true로 설정합니다. 내가 잘못 여기서 뭘하는지에 관해서는

public static void premain(String agentArgs, Instrumentation inst) { 
    inst.addTransformer(new PyClassFileTransformer(inst), true); 
} 

모든 통찰력 : 나는 에이전트의 premain 방법으로 계측에 변압기를 추가 할 때 또한, 나는 이렇게? 감사.

+1

문제가 해결 되었습니까? @Jens 나에게 몇 가지 조언을주고 [여기] (http://stackoverflow.com/questions/18657095/got-unsupportedoperationexception-when-try-to-retransformclasses) 갈 수 있습니까? –

답변

1

바이트 코드 계측 전략을 변경할 수 있으므로 클래스 B가로드 될 때 클래스 B를 지금 수정해야하는 경우 모든 하위 클래스를 찾아 해당 시점을 결정하십시오. 클래스 메타 데이터 저장소 또는 캐시를 메모리에 유지 (클래스 계층 구조에 대한 정보)하여 최적화 할 수 있으므로 매번 메타 데이터를로드 할 필요가 없습니다.