Java javassist 方法调用
Java javassist method calling
所以我将 java 代理与 javassist 一起使用,目的是将一些与监控相关的小代码注入不同 类 中的不同方法。
我的java代理代码:
public class ConverterAgent implements ClassFileTransformer {
public static void premain(String args, Instrumentation instrumentation){
System.out.println(">>>>>>>>>> Intializing Java agent <<<<<<<<<<");
ConverterAgent transformer = new ConverterAgent();
instrumentation.addTransformer(transformer);
}
public static void agentmain(String args, Instrumentation instrumentation){
System.out.println(">>>>>>>>>> Intializing Java agent <<<<<<<<<<");
ConverterAgent transformer=new ConverterAgent();
instrumentation.addTransformer(transformer);
}
@Override
public byte[] transform(final ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDoman,
byte[] classFileBuffer)
throws IllegalClassFormatException {
//javassist code goes here
return classFileBuffer;
}
}
我的 javassist 注射看起来像这样:
if ("className1".equals(className)){
//code
}
if ("className2".equals(className)){
//same code as in first class
}
if ("className3".equals(className)){
//same code as in first and second class
}
所以我多次注入完全相同的代码,我想优化我的过程并为每次注入调用一个方法,这样我就不必一遍又一遍地复制相同的代码。但这就是我遇到问题的地方,我应该使用什么方法类型以及除了 Class 和方法名称之外它还需要什么参数。
将 class 字节码转换为您的转换方法,然后 return 修改“新”class 字节码。
这意味着您肯定return 是包含转换方法所需信息的字节[]。
所以你的方法应该是这样的:
public class DynamicTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
// into the transformer will arrive every class loaded so you filter
// to match only what you need
if (className.equals("com/full/path/to/be/instrumented/className1") ||
className.equals("com/full/path/to/be/instrumented/className2") ||
className.equals("com/full/path/to/be/instrumented/className3") ) {
byteCode = myMethodThatTransform(className, byteCode);
}
return byteCode;
}
public byte[] myMethodThatTransform(String className, byte[] byteCode){\
try {
// retrive default Javassist class pool
ClassPool cp = ClassPool.getDefault();
// get from the class pool our class with this qualified name
CtClass cc = cp.get(className);
// get all the methods of the retrieved class
CtMethod[] methods = cc.getDeclaredMethods()
for(CtMethod meth : methods) {
// The instrumentation code to be returned and injected
final StringBuffer buffer = new StringBuffer();
String name = meth.getName();
// just print into the buffer a log for example
buffer.append("System.out.println(\"Method " + name + " executed\" );");
meth.insertBefore(buffer.toString())
}
// create the byteclode of the class
byteCode = cc.toBytecode();
// remove the CtClass from the ClassPool
cc.detach();
} catch (Exception ex) {
ex.printStackTrace();
}
return byteCode;
}
}
所以我将 java 代理与 javassist 一起使用,目的是将一些与监控相关的小代码注入不同 类 中的不同方法。
我的java代理代码:
public class ConverterAgent implements ClassFileTransformer {
public static void premain(String args, Instrumentation instrumentation){
System.out.println(">>>>>>>>>> Intializing Java agent <<<<<<<<<<");
ConverterAgent transformer = new ConverterAgent();
instrumentation.addTransformer(transformer);
}
public static void agentmain(String args, Instrumentation instrumentation){
System.out.println(">>>>>>>>>> Intializing Java agent <<<<<<<<<<");
ConverterAgent transformer=new ConverterAgent();
instrumentation.addTransformer(transformer);
}
@Override
public byte[] transform(final ClassLoader loader,
String className,
Class<?> classBeingRedefined,
ProtectionDomain protectionDoman,
byte[] classFileBuffer)
throws IllegalClassFormatException {
//javassist code goes here
return classFileBuffer;
}
}
我的 javassist 注射看起来像这样:
if ("className1".equals(className)){
//code
}
if ("className2".equals(className)){
//same code as in first class
}
if ("className3".equals(className)){
//same code as in first and second class
}
所以我多次注入完全相同的代码,我想优化我的过程并为每次注入调用一个方法,这样我就不必一遍又一遍地复制相同的代码。但这就是我遇到问题的地方,我应该使用什么方法类型以及除了 Class 和方法名称之外它还需要什么参数。
将 class 字节码转换为您的转换方法,然后 return 修改“新”class 字节码。
这意味着您肯定return 是包含转换方法所需信息的字节[]。
所以你的方法应该是这样的:
public class DynamicTransformer implements ClassFileTransformer {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] byteCode = classfileBuffer;
// into the transformer will arrive every class loaded so you filter
// to match only what you need
if (className.equals("com/full/path/to/be/instrumented/className1") ||
className.equals("com/full/path/to/be/instrumented/className2") ||
className.equals("com/full/path/to/be/instrumented/className3") ) {
byteCode = myMethodThatTransform(className, byteCode);
}
return byteCode;
}
public byte[] myMethodThatTransform(String className, byte[] byteCode){\
try {
// retrive default Javassist class pool
ClassPool cp = ClassPool.getDefault();
// get from the class pool our class with this qualified name
CtClass cc = cp.get(className);
// get all the methods of the retrieved class
CtMethod[] methods = cc.getDeclaredMethods()
for(CtMethod meth : methods) {
// The instrumentation code to be returned and injected
final StringBuffer buffer = new StringBuffer();
String name = meth.getName();
// just print into the buffer a log for example
buffer.append("System.out.println(\"Method " + name + " executed\" );");
meth.insertBefore(buffer.toString())
}
// create the byteclode of the class
byteCode = cc.toBytecode();
// remove the CtClass from the ClassPool
cc.detach();
} catch (Exception ex) {
ex.printStackTrace();
}
return byteCode;
}
}