2016-03-13 6 views
1

Различные источники предлагают различные способы реализации ClassFileTransformer с Javassist:ClassFileTransformer реализации с Javassist

blog.newrelic.com/2014/09/29/diving-bytecode-manipulation-creating-audit-log-asm-javassist/

public byte[] transform(...) { 
    ClassPool pool = ClassPool.getDefault(); // Edited to simplify 
    pool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer)); 
    CtClass cclass = pool.get(className.replaceAll("/", ".")); 
    ... 
    return cclass.toBytecode(); 
} 

blog.javabenchmark.org/2013/05/java-instrumentation-tutorial.html

public byte[] transform(...) { 
    ClassPool cp = ClassPool.getDefault(); 
    CtClass cc = cp.get("org.javabenchmark.instrumentation.Sleeping"); 
    ... 
    return cc.to:byteCode(); // edited to simplify 
} 

http://javapapers.com/core-java/java-instrumentation/

public byte[] transform(...) { 
    ClassPool classPool = ClassPool.getDefault(); 
    CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer)); 
    ... 
    return ctClass.to:byteCode(); // edited to simplify 
} 

Какой самый правильный путь и почему? Есть ли другие решения, которые лучше, чем эти три?

https://stackoverflow.com/a/26725215/776884 упоминает настройки правильного загрузчика классов. Требуется ли при использовании инструментария API? Должен ли использоваться ClassPool classPool = new ClassPool() с CtClass.makeClass() с инсталляционным API?

ответ

1

Все примеры неверны и не будут работать в общей установке. Вы никогда не должны использовать пул классов по умолчанию, и вы никогда не должны - как показано в новом блоге реликвии, - делиться пулом классов между трансформаторами, поскольку вы не можете сказать, связаны ли загруженные классы их загрузчиком классов.

Рассмотрите сервер приложений, где приложение всегда имеет свой собственный загрузчик классов; вы даже не могли видеть преобразованные классы, используя пул классов по умолчанию (который ссылается на загрузчик системного класса, т. е. путь к классу), и вы не можете обещать, что все приложения на сервере приложений будут запускать ту же версию какого-либо класса, если они оба содержат их.

Единственное правильное решение:

ClassPool classPool = new ClassPool(); 
classPool.appendClassPath(new LoaderClassPath(loader)); 
CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer)); 

Таким образом, если принять во внимание, что каждый класс загружен другим загрузчиком класса, который может представлять различные точки зрения, т.е. содержат различные классы или другую версию класса чем путь к классу, и вы все еще разбираете предоставленный массив байтов, который может содержать новые члены, которые были добавлены ранее активированными трансформаторами другими агентами Java.

+0

Спасибо. Мне пришлось попробовать использовать ClassPool classPool = new ClassPool(); 'прежде чем я полностью понял, что classpool для генерации кода. Получение ошибок об отсутствующем классе класса помогло понять это. – jikuja