尝试在 Web 应用程序中使用 Agent 进行字节码操作
Try to use Agent in Webapplication for bytecode Manupulation
我在 Java 方面表现不佳,但我的 webApplication 运行 在 Wildfly 上。
我有 3 个线程,它们只调用一个插入日志的函数,该函数将日志保存到数据库中,之后每个线程发送一个时间来执行此操作需要多长时间。
他们将数据发送到我编写的另一个程序,该程序具有 3 个线程来调用 3 个服务器线程之一。
所以现在我尝试做一些字节码操作,服务器上的每个线程都会保存日期时间调用,日志函数等待 1 秒,returns 然后是他们需要的时间。
1 线程在等待 1 秒之前或之后在日志文件中写入内容。
但是这部分他们等待一秒钟并调用日志函数,我希望它通过字节码操作注入到每 3 个线程中。
public class MyTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
return transformClass(redefiningClass, bytes);
}
private byte[] transformClass(Class classToTransform, byte[] b) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.get("de.soptim.ws.MyApplication");
} catch (javassist.NotFoundException e) {
e.printStackTrace();
}
try {
assert cl != null;
CtMethod[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
changeMethod(methods[i]);
}
}
b = cl.toBytecode();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
private void changeMethod(CtMethod method) throws NotFoundException, CannotCompileException {
if (method.hasAnnotation(Loggable.class)) {
method.insertBefore("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
method.insertAfter("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
}
}}
那是我的转换器 class 它应该增加我的方法需要的代码 它检查什么方法有 @Loggable 注释然后将代码添加到其中("at the moment it's just some log statments for checking if it works")
我现在最大的问题是我不知道如何调用我的代理...我用 google 搜索 hwo 以在运行时使用 agentmain() 调用代理,但我想我并不真正理解它是如何工作的。
特工Class
public class LogAgent {
public static void agentmain(String agentArgs, Instrumentation inst) {
System.out.println("Starting the agent");
inst.addTransformer(new MyTransformer());
}}
希望你理解我的问题 :) 如果你回答我,请尽量保持新手友好 :D。
你没有明确地调用你的代理,你应该为你的 JVM 指定额外的参数:
java -javaagent:jarpath[=options]
其中 jarpath
是包含您的代理的 jar 的路径。 JVM 将在 java 程序的 main
方法之前调用 premain
方法。
并且 transform
方法将在 JVM 加载类之前调用(您没有显式调用它)。
最后一句话:您应该实施 premain
方法,而不是 agentmain
。
agentmain
在附加到 运行 vm 期间使用,而 premain
在使用 -javaagent
方法启动 JVM 时使用。
并确保您的 jar 具有有效清单,如下所述:https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html
我没有使用 javaassit 所以我不能说你的代码是有效的,但是检测像 Wildfly 这样的 webapp 服务器比普通的 java 应用程序要难得多(主要是由于类加载器的可见性和层次结构)。
另见:
http://www.tomsquest.com/blog/2014/01/intro-java-agent-and-bytecode-manipulation/
Tutorials about javaagents
我在 Java 方面表现不佳,但我的 webApplication 运行 在 Wildfly 上。 我有 3 个线程,它们只调用一个插入日志的函数,该函数将日志保存到数据库中,之后每个线程发送一个时间来执行此操作需要多长时间。 他们将数据发送到我编写的另一个程序,该程序具有 3 个线程来调用 3 个服务器线程之一。
所以现在我尝试做一些字节码操作,服务器上的每个线程都会保存日期时间调用,日志函数等待 1 秒,returns 然后是他们需要的时间。
1 线程在等待 1 秒之前或之后在日志文件中写入内容。 但是这部分他们等待一秒钟并调用日志函数,我希望它通过字节码操作注入到每 3 个线程中。
public class MyTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
return transformClass(redefiningClass, bytes);
}
private byte[] transformClass(Class classToTransform, byte[] b) {
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.get("de.soptim.ws.MyApplication");
} catch (javassist.NotFoundException e) {
e.printStackTrace();
}
try {
assert cl != null;
CtMethod[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].isEmpty() == false) {
changeMethod(methods[i]);
}
}
b = cl.toBytecode();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cl != null) {
cl.detach();
}
}
return b;
}
private void changeMethod(CtMethod method) throws NotFoundException, CannotCompileException {
if (method.hasAnnotation(Loggable.class)) {
method.insertBefore("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
method.insertAfter("threadLogger.info(\"ADDED THIS FROM BYTECODE !!!\");");
}
}}
那是我的转换器 class 它应该增加我的方法需要的代码 它检查什么方法有 @Loggable 注释然后将代码添加到其中("at the moment it's just some log statments for checking if it works")
我现在最大的问题是我不知道如何调用我的代理...我用 google 搜索 hwo 以在运行时使用 agentmain() 调用代理,但我想我并不真正理解它是如何工作的。
特工Class
public class LogAgent {
public static void agentmain(String agentArgs, Instrumentation inst) {
System.out.println("Starting the agent");
inst.addTransformer(new MyTransformer());
}}
希望你理解我的问题 :) 如果你回答我,请尽量保持新手友好 :D。
你没有明确地调用你的代理,你应该为你的 JVM 指定额外的参数:
java -javaagent:jarpath[=options]
其中 jarpath
是包含您的代理的 jar 的路径。 JVM 将在 java 程序的 main
方法之前调用 premain
方法。
并且 transform
方法将在 JVM 加载类之前调用(您没有显式调用它)。
最后一句话:您应该实施 premain
方法,而不是 agentmain
。
agentmain
在附加到 运行 vm 期间使用,而 premain
在使用 -javaagent
方法启动 JVM 时使用。
并确保您的 jar 具有有效清单,如下所述:https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html
我没有使用 javaassit 所以我不能说你的代码是有效的,但是检测像 Wildfly 这样的 webapp 服务器比普通的 java 应用程序要难得多(主要是由于类加载器的可见性和层次结构)。
另见:
http://www.tomsquest.com/blog/2014/01/intro-java-agent-and-bytecode-manipulation/ Tutorials about javaagents