오늘은 어디로 갈까...

Instrumentation.redefineClasses 본문

無汗不成

Instrumentation.redefineClasses

剛宇 2009. 5. 11. 18:14
 삽질하다가 전혀 엉뚱한것을 발견(?) ^^;
 그놈의 정체는 JPDA(Java Platform Debugger Architecture) 
 http://java.sun.com/javase/technologies/core/toolsapis/jpda/
 이클립스의 디버그 모드는 가끔 사용하기는 하지만, 이게 API로 제공되고 있을줄이야... ^^;
 com.sun.jdi 패키지인데, tools.jar에 포함되어 있다.



 본론(?)으로 돌아가서, Javarebel은 어떻게 돌아가는지 파악하는데 또다시 실패했으나, Instrumentation의 redefineClasses() 메소드를 이용해서, 아주 간단하게 클래스를 변경하는 방법을 테스트해본것에 대해서 만족을..... ^^;
 여러가지 제약사항이 존재하기는 하나, 추가/수정은 잘 되는거 같음. 아래는 Javassist(http://www.csg.is.titech.ac.jp/~chiba/javassist/tutorial/tutorial.html)를 이용해서 간단히 메소드 변경을 해본것.
package kr.kangwoo.test;

import java.lang.instrument.ClassDefinition;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class MyPreLoader implements ClassFileTransformer, Runnable {

	public final Instrumentation instrumentation;
	
	
	public MyPreLoader(Instrumentation instrumentation) {
		this.instrumentation = instrumentation;
	}
	
	public static void premain(String agentArgument, Instrumentation instrumentation) {
		System.out.println("premain");
		MyPreLoader l = new MyPreLoader(instrumentation);
		instrumentation.addTransformer(l);
		
		Thread t = new Thread(l);
		t.start();
	}

	public byte[] transform(ClassLoader loader, String className,
			Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
			byte[] classfileBuffer) throws IllegalClassFormatException {
		System.out.println("transform : " + className);
		return classfileBuffer;
	}
	
	public void hello() {
		System.out.println("안녕하세요");
	}

	public void run() {
		for (int i = 0; i < 10; i++) {
			try {
				Thread.sleep(1 * 1000);
				
				ClassPool pool = ClassPool.getDefault();
				CtClass cc = pool.get("kr.kangwoo.test.MyPreLoader");
				cc.defrost();
				CtMethod m = cc.getDeclaredMethod("hello");
				m.setBody("{ System.out.println(\"오~! 변한다~ : " + i + "번째\"); }");
	
				ClassDefinition[] cd = new ClassDefinition[1];
				cd[0] = new ClassDefinition(MyPreLoader.class, cc.toBytecode());
				instrumentation.redefineClasses(cd);
			} catch (Exception e) {
				e.printStackTrace();
			}
			hello();
		}
		
	}

}