Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中有没有一种方法可以通过使用插装来拦截对象的创建?_Java_Exception_Instrumentation - Fatal编程技术网

Java中有没有一种方法可以通过使用插装来拦截对象的创建?

Java中有没有一种方法可以通过使用插装来拦截对象的创建?,java,exception,instrumentation,Java,Exception,Instrumentation,我需要截获所有ClassNotFoundException或NoClassDefError的创建:问题是这些异常中的一些被一些库捕获,并在其他异常类型中重新引用,因此我无法检索类名。 在Java中,有没有一种方法可以通过使用Intstrumentation来实现这一点?您可以编写自己的实现,并将您的逻辑应用到或其他可用的方法中ClassLoader是应用程序中ClassNotFoundException的常见来源。除非第三方库更改默认的类加载过程(例如OSGI),否则它们仍将调用您的类加载程序以

我需要截获所有ClassNotFoundException或NoClassDefError的创建:问题是这些异常中的一些被一些库捕获,并在其他异常类型中重新引用,因此我无法检索类名。
在Java中,有没有一种方法可以通过使用Intstrumentation来实现这一点?

您可以编写自己的实现,并将您的逻辑应用到或其他可用的方法中
ClassLoader
是应用程序中
ClassNotFoundException
的常见来源。除非第三方库更改默认的类加载过程(例如OSGI),否则它们仍将调用您的
类加载程序
以下示例向
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);
        }
    }

}
并使用程序参数
-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)

这在ASM中是可能的。我以前做过一些事情来改变内置java类的行为——看到了吗?您可以转换显式创建这些类的实例的类。但我怀疑您是否能够拦截JVM本身创建的
NoClassDefError
实例。我尝试过使用Java.lang.instrument.Instrumentation.addTransformer(ClassFileTransformer)编写Java代理,并使用System.out.println()记录所有类。不知何故,如果类没有被指令插入“看到”,您就不会发现异常。我认为这个类肯定有一些“特殊”的地方。是的,但是我怀疑JVM在内部构造错误时调用构造函数。我需要拦截这个异常,因为所有运行时类加载器都使用委托模型,如果无法加载类,子类加载器将调用父类加载器。您应该能够使用
try/catch
包装对
super
的调用,并在重新抛出异常之前发现异常。如果在类路径中有一个库直接使用我的类加载器的父类加载器,它将不会works@KarolDowbecki只有在自定义类上调用了
loadClass
时,此选项才有效加载器。一旦您返回一个通过
super
调用解析的类,它的所有依赖项都将通过父加载程序直接解析。非常感谢,我将尝试它
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)