Một cách kiểm tra việc sử dụng chính xác EDT của toàn bộ ứng dụng là sử dụng tác nhân java. Mã dưới đây là phiên bản cải tiến của Đại lý được đăng theo số Debugging Swing, the final Summary. Nó hoạt động với ASM 4.1. Tạo một Jar chứa asm-all-4.1.jar (unpacked), mã được biên dịch và một tệp kê khai chỉ rõ tác nhân là Premain-Class và bắt đầu.
/**
* A java agent which transforms the Swing Component classes in such a way that a stack
* trace will be dumped or an exception will be thrown when they are accessed from a wrong thread.
*
* To use it, add
* <pre>
* -javaagent:${workspace_loc:MyProject/tool/util/swingEDTCheck}/swingEDTCheck.jar
* </pre>
*
* to the VM arguments of a run configuration. This will cause the stack traces to be dumped.
*
* Use
* <pre>
* -javaagent:${workspace_loc:MyProject/tool/util/swingEDTCheck}/swingEDTCheck.jar=throw
* </pre>
* to throw exceptions.
*
*/
public class SwingEDTCheckAgent {
public static void premain(String args, Instrumentation inst) {
boolean throwing = false;
if ("throw".equals(args)) {
throwing = true;
}
inst.addTransformer(new Transformer(throwing));
}
private static class Transformer implements ClassFileTransformer {
private final boolean throwing;
public Transformer(boolean throwing) {
this.throwing = throwing;
}
@Override
public byte[] transform(ClassLoader loader,
String className,
Class classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer)
throws IllegalClassFormatException {
// Process all classes in javax.swing package which names start with J
if (className.startsWith("javax/swing/J")) {
ClassReader cr = new ClassReader(classfileBuffer);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new EdtCheckerClassAdapter(cw, throwing);
cr.accept(cv, 0);
return cw.toByteArray();
}
return classfileBuffer;
}
}
private static class EdtCheckerClassAdapter extends ClassVisitor {
private final boolean throwing;
public EdtCheckerClassAdapter(ClassVisitor classVisitor, boolean throwing) {
super(Opcodes.ASM4, classVisitor);
this.throwing = throwing;
}
@Override
public MethodVisitor visitMethod(final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
MethodVisitor mv =
cv.visitMethod(access, name, desc, signature, exceptions);
if (name.startsWith("set") || name.startsWith("get") || name.startsWith("is")) {
return new EdtCheckerMethodAdapter(mv, throwing);
} else {
return mv;
}
}
}
private static class EdtCheckerMethodAdapter extends MethodVisitor {
private final boolean throwing;
public EdtCheckerMethodAdapter(MethodVisitor methodVisitor, boolean throwing) {
super(Opcodes.ASM4, methodVisitor);
this.throwing = throwing;
}
@Override
public void visitCode() {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/awt/EventQueue", "isDispatchThread", "()Z");
Label l1 = new Label();
mv.visitJumpInsn(Opcodes.IFNE, l1);
Label l2 = new Label();
mv.visitLabel(l2);
if (throwing) {
// more Aggressive: throw exception
mv.visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException");
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn("Swing Component called from outside the EDT");
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
mv.visitInsn(Opcodes.ATHROW);
} else {
// this just dumps the Stack Trace
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "dumpStack", "()V");
}
mv.visitLabel(l1);
}
}
}
Hãy xem tại địa chỉ: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html – kiheru
các chiến lược kiểm tra điển hình là theo chiều ngược lại: họ tìm những nơi mà bạn truy cập các thành phần Swing ngoài EDT (so với kiểm tra xem mã chạy dài có xảy ra trên EDT) hay không, không thể thêm mã vào vị trí mà bạn cho là dài hạn – kleopatra
ANd như thế nào tìm nơi bạn truy cập các thành phần Swing ngoài EDT? – dendini