有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!


共 (2) 个答案

  1. # 1 楼答案

    您可以编写自己的^{}实现,并在^{}或其他可用方法中应用您的逻辑ClassLoader是应用程序中{}的常见来源。除非第三方库更改默认的类加载过程(例如OSGI),否则它们仍然会调用ClassLoader

  2. # 2 楼答案

    下面的示例向ClassNotFoundException的构造函数添加插装,并在调用它时执行System.err.println

    我不确定如何从我认为您需要的检测调用回调

    import java.lang.instrument.ClassFileTransformer;
    import java.lang.instrument.IllegalClassFormatException;
    import java.lang.instrument.Instrumentation;
    import java.lang.instrument.UnmodifiableClassException;
    import java.security.ProtectionDomain;
    
    import net.bytebuddy.jar.asm.ClassReader;
    import net.bytebuddy.jar.asm.ClassVisitor;
    import net.bytebuddy.jar.asm.ClassWriter;
    import net.bytebuddy.jar.asm.MethodVisitor;
    import net.bytebuddy.jar.asm.Opcodes;
    
    public class ClassNotFoundExceptionIntercept {
    
        public static void premain(String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
            inst.addTransformer(new ClassFileTransformer() {
                @Override
                public byte[] transform(ClassLoader l, String name, Class<?> c, ProtectionDomain d, byte[] b)
                        throws IllegalClassFormatException {
                    if ("java/lang/ClassNotFoundException".equals(name)) {
                        return instrument(b);
                    }
                    return b;
                }
            }, true);
            inst.retransformClasses(java.lang.ClassNotFoundException.class);
        }
    
        private static byte[] instrument(byte[] originalBytes) {
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
            ClassAdapter adapter = new ClassAdapter(cw);
            ClassReader cr = new ClassReader(originalBytes);
            cr.accept(adapter, ClassReader.SKIP_FRAMES);
            return cw.toByteArray();
        }
    
        public static class ClassAdapter extends ClassVisitor implements Opcodes {
            public ClassAdapter(ClassVisitor cv) {
                super(ASM4, cv);
            }
            @Override
            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature,
                    String[] exceptions) {
                if ("<init>".equals(name)) {
                    MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
                    return new Wrapper(mv);
                } else {
                    return super.visitMethod(access, name, descriptor, signature, exceptions);
                }
            }
        }
    
        private static class Wrapper extends MethodVisitor {
            public Wrapper(MethodVisitor mv) {
                super(Opcodes.ASM4, mv);
            }
            @Override
            public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
                mv.visitMethodInsn(opcode, owner, name, desc, itf);
    
                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "err", "Ljava/io/PrintStream;");
                mv.visitLdcInsn("Constructor invoked");
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            }
        }
    
    }
    

    这需要编译成带有META-INF/MANIFEST的JAR文件。像这样吗

    Manifest-Version: 1.0
    Premain-Class: ClassNotFoundExceptionIntercept
    Agent-Class: ClassNotFoundExceptionIntercept
    Can-Retransform-Classes: true
    Can-Redefine-Classes: true
    

    并使用程序参数-javaagent:/home/adam/agent-example.jar调用

    这可以用一个包含异常的测试类来演示

    public class Test {
    
        public static void main(String[] args) {
            try {
                Class.forName("brexit");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    输出

    Constructor invoked
    Constructor invoked
    Constructor invoked
    java.lang.ClassNotFoundException: brexit
        at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:264)
        at Test.main(Test.java:9)