2013-07-09 6 views
0

나는 컴파일러 프로젝트를위한 ASM API를 배우기 시작했다. 자바 에이전트 개발을 위해 Java Instrumentation과 ASM ByteCode Library를 사용하고 있습니다.서버를 시작한 후 런타임에 className과 methodName을 ASM 파서의 ClassVisitor() 및 methodVisitor()에 전달할 수 있습니까?

속성을 통해 클래스 이름과 메소드 이름을 전달 중입니다. 내 목표는 런타임에 className과 methodName을 변경하는 것입니다. 이는 서버를 시작한 후 또는 premain()을 호출 한 후이를 의미합니다.

하지만 className 또는 packageName이 시작된 서버 전에 전달 된 항목에 대해서만 작동합니다.

나는 javaagent (premain())를 호출하는 동안 주어진 pakage/class에 대한 메소드에 대해 ASM set visitor를 이해한다.

서버가 시작되거나 premain()이 호출 된 후에도 특정 클래스와 메서드를 방문하려고했습니다.

매우 도움이 될 것입니다.

이것은 현재 실행중인 프로그램입니다.

 public class AddPrintlnAgent implements ClassFileTransformer { 

    public static void premain(String agentArgs, Instrumentation inst) { 
    Properties prop = new Properties(); 

    try { 
     prop.load(new FileInputStream("C:\\locator.properties")); 

    } catch (FileNotFoundException e) { 

     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    inst.addTransformer(new AddPrintlnAgent()); 
} 

public byte[] transform(ClassLoader loader, String className, 
     Class<?> classBeingRedefined, ProtectionDomain protectionDomain, 
     byte[] classfileBuffer) throws IllegalClassFormatException { 

    byte[] retVal = null; 

    if (className.equals(className)) { 
     ClassWriter cw = new ClassWriter(0); 
     ClassVisitor ca = new MyClassAdapter(cw); 
     ClassReader cr = new ClassReader(classfileBuffer); 
     cr.accept(ca, 0); 
     retVal = cw.toByteArray(); 
    } 
    return retVal; 
} 

public class MyClassAdapter extends ClassNode implements Opcodes { 
    private ClassVisitor cv; 
    Properties prop = new Properties(); 
    public MyClassAdapter(ClassVisitor cv) { 
     this.cv = cv; 

    } 
    @Override 
    public void visitEnd() { 
     try { 
      prop.load(new FileInputStream("C:\\locator.properties")); 
     } catch (FileNotFoundException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     for (MethodNode mn : (List<MethodNode>) methods) { 
      if (mn.name.equals(prop.getProperty("methodName").trim())) { 
      InsnList il = new InsnList(); 

      il.add(new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); 
      il.add(new LdcInsnNode(prop.getProperty("message"))); 
      il.add(new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", 
         "println", "(Ljava/lang/String;)V")); 
      mn.instructions.insert(il); 

      mn.maxStack +=2;      
      } 
     } 
     accept(cv); 
    } 

} 

} 사전에

감사

사티시 V J 당신은 정리 코드를해야

+0

내가 틀렸다고 정정하되'if (className.equals (className)) {'는 항상 true를 반환해야하므로 모든 클래스에 대해 바이트 코드를 다시 작성해야합니다. 또한 "className과 methodName을 변경하십시오"라는 것이 정확히 무엇을 의미합니까? 특정 클래스와 메소드의 이름을 변경하려고하십니까? – vijay

답변

0

. premain 메서드에서는 Properties 개체에 속성 파일을로드하지만 그 인스턴스는 사용되지 않습니다. 대신 visitEnd() 호출마다 해당 파일을 다른 Properties 인스턴스로 다시로드합니다. 이것이 정말로 당신이 원하는 것인지 확실하지 않습니다.

그러나 변압기는 클래스로드 중에 호출되지만 이미로드 된 클래스에는 호출되지 않습니다. 로드 된 클래스를 재 변환하거나 다시 정의 할 수는 있지만로드 후 클래스 또는 메소드 이름을 변경하는 것은 계측에서 지원되지 않습니다.