【发布时间】:2013-08-10 21:02:03
【问题描述】:
好的,我正在尝试做一个 Java 代理来监控应用程序。所以,我试图在 PreparedStatements 中注入代码来测量 SQL 查询的执行时间。为此,我开发了一个实现 ClassFileTransformer 的类。看起来是这样的:
public class JDBCClassTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
ClassPool pool = ClassPool.getDefault();
CtClass currentClass = null;
CtClass statement = null;
try {
currentClass = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
statement = pool.get("java.sql.PreparedStatement");
if (currentClass.subtypeOf(statement) && !currentClass.isInterface()) {
probeStatement(currentClass);
}
classfileBuffer = currentClass.toBytecode();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (currentClass != null) {
currentClass.detach();
}
}
return classfileBuffer;
}
private void probeStatement(CtClass currentClass) throws NotFoundException, CannotCompileException {
CtField field = CtField.make("private fr.mael.package.SQLProbe $$probe;", currentClass);
currentClass.addField(field);
CtMethod setter = CtNewMethod.make("public void set$$probe(fr.mael.package.SQLProbe probe){ this.$$probe = probe;}", currentClass);
currentClass.addMethod(setter);
CtMethod executeQuery = currentClass.getMethod("executeQuery", "()Ljava/sql/ResultSet;");
executeQuery.insertBefore("this.$$probe.start();");
executeQuery.insertAfter("this.$$probe.stop();");
}
}
所以,我想做的是在每个实现 java.sql.PreparedStatement 的类中(在“executeQuery()”方法中)注入代码。 为了测试它,我只是在 MySQL 数据库上运行一个基本的“select * from a_table”,代理连接到 JVM。但我收到以下异常:
javassist.CannotCompileException: [source error] no such field: $$probe
at javassist.CtBehavior.insertBefore(CtBehavior.java:725)
at javassist.CtBehavior.insertBefore(CtBehavior.java:685)
它发生在executeQuery.insertBefore("this.$$probe.start();"); 线上。
奇怪的是,每次执行“probeStatement”方法时都不会发生这种情况:首先为类com.mysql.jdbc.PreparedStatement调用该方法,并且没有抛出异常。然后,为类com.mysql.jdbc.ServerPreparedStatement 调用该方法。抛出异常。类com.mysql.jdbc.JDBC4PreparedStatement 也调用了该方法,并且也抛出了异常。 ServerPreparedStatement 和 JDBC4PreparedStatementextend com.mysql.jdbc.PreparedStatement 所以也许它在某种程度上是相关的......
我是 javassist 和 java 代理的新手,所以答案可能很明显,但我不明白为什么会抛出这个异常。
【问题讨论】:
标签: java javassist javaagents