보통 bytecode instrumentation을 할 때 cglib, javassist등과 같은 도구를 사용하는 데 JVM 스펙상 이미 로드된 클래스코드에 대한 수정을 허용하지 않기 때문에(만약 조작한다 하더라도 그 코드는 의미가 없을 수 있다고 판단됩니다) javaagent의 premain을 이용하여 로드시점에 대상들에 대한 바이트 코드 조작이 필요합니다.
이 때 javassist를 사용하고 있는데 보통 WAS의 경우 다양한 클래스 로더(예 : EAR, Web, EJB 등)들을 가지고 있기 때문에 javassist에서 해당 클래스들에 대한 참조를 하지 못해 NotFoundException으로 인한 toClass등의 메소드에서 CannotCompileException이 발생합니다.
아래의 예제는 javaagent premain + ClassFileTransformer의 뼈대 코드로 WAS 클래스로더로 로딩되는 클래스를 참조할 수 있도록 합니다.
public static void premain(String agentArgs, Instrumentation inst) {
if (agentArgs != null) {
String[] args = agentArgs.split("( *)|(, *)");
parseArgs(args);
}
if( dbtrace ) {
if( verbose ) {
System.out.println("JDBC Query Monitoring turns on");
}
ClassFileTransformer transformer = new JDBCClassInstrumentor();
inst.addTransformer(transformer);
}
if( packageName != null ) {
if( verbose ) {
System.out.println("Package Profiler Work Start for [" + packageName + "]");
packageName = packageName.replace('.', '/');
}
ClassFileTransformer transformer = new HttpServletClassTransformer();
inst.addTransformer(transformer);
}
}
public JDBCClassInstrumentor() {
cp = ClassPool.getDefault();
}
HashMap loaderMap = new HashMap();
@Override
public byte[] transform(ClassLoader loader, String className,
Class> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
try {
if (loader != null && !loaderMap.containsValue(loader)) {
// System.out.println(loader +
// " is added as a new classloader");
loaderMap.put(loader.toString(), loader);
cp.insertClassPath(new LoaderClassPath(loader));
}
if (className.equals("org/jboss/resource/adapter/jdbc/WrappedConnection")) {
// Your Work!
}
} catch (Exception e) {
e.printStackTrace();
}
return modified_bytecode
}
http://www.javapattern.info/trackback/327





