Java:给定类加载器和类,获取类字节码

标签 java classloader bytecode

我有以下场景,我有一个类加载器和它加载的一个类,现在我需要那个类的字节码。到目前为止,这是我尝试过的:

    Field f = ClassLoader.class.getDeclaredField("classes");
    f.setAccessible(true);

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Vector<Class> classes =  (Vector<Class>) f.get(classLoader);

    for(Class loadedClass : classes)
    {
        String className = loadedClass.getName();
        String classFileResourcePath = "/" + className.replace(".", "/") + ".class";
        InputStream inputStream = classLoader.getResourceAsStream(classFileResourcePath);
        System.out.println(">>>> " + className + " => " + classFileResourcePath + " => " + inputStream);
    }

此代码为每个类文件打印 null。但是,当我将它更改为 classLoader.getClass().getResourceAsStream(classFileResourcePath) 时,如果在 IDE 中的独立主类中运行,它就可以工作,但是当我到达需要它的实际上下文时,这也返回 null,大概是因为 jar 和幕后的类发生了“特殊”的事情。在无法讨论这些细节的情况下,只需说明我拥有的是一个类和加载它的类加载器,现在我需要字节码。我该怎么做呢?如果这在 Java 层中是不可能的,我也许能够获取原始 Jar 本身并将其作为 zip 文件读取,但那将是最后的手段。

最佳答案

您的代码示例实际上存在几个问题:

首先,您访问 java.lang.ClassLoader 类的“classes”字段以确定已经加载了哪些类。这是一个私有(private)字段,如果您让您的代码在使用专门类加载器(java.lang.ClassLoader 的子类)的环境中运行,您或多或少不知道该字段中包含什么。

使用 ClassLoader.getResourceAsStream, 您在路径前加上“/”,这是不正确的。 ClassLoader.getResourceAsStream 需要一个绝对路径并且该路径以第一个段的名称开头,例如使用 ClassLoader.getResourceAsStream("java/lang/ClassLoader.class") 而不是 ClassLoader.getResourceAsStream("/java/lang/ClassLoader.class")

使用 Class.getResourceAsStream,您可以提供以“/”开头的绝对路径,或者提供相对于相关类的路径,而不是以“/”开头。例如。 ClassLoader.class.getResourceAsStream("ClassLoader.class")ClassLoader.class.getResourceAsStream("/java/lang/ClassLoader.class") 通常都会给你访问权限到类的字节码。

然而,这两种方法都需要使用 Java 运行时环境的标准命名约定,将类文件作为类路径上的资源提供。没有要求 Java 运行时环境必须以这种方式运行。 Java 类可能是动态生成的,导致它们被类加载器识别,但不受持久字节代码的支持。专有类加载器也不需要使用与标准类加载器相同的类名和资源路径之间的映射。

Java 类加载器也不提供公共(public) API 来访问类的字节码。如果您将 VM 分为“ native 代码部分”和“Java 代码部分”,那么很明显,VM 通常不需要从“Java 代码部分”引用原始字节码。

依靠标准类加载器使用的约定,您可以使用您的方法,它主要适用于独立应用程序。但是正如您自己发现的那样,如果您在不同的环境中运行代码,它可能会失败,例如部署到应用程序服务器或使用 OSGi 等打包框架时。

关于Java:给定类加载器和类,获取类字节码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26637137/

相关文章:

java - 将字符串匹配为二维整数数组的正则表达式

java - Kubernetes Continuous Deploy插件出现问题

java - 在tomcat集群环境中获取ClassNotFoundException反序列化 session 属性

java - 检查 Java 字节码是否包含调试符号

Python 不解释已更改的文件,使用过时的 .pyc

java - 由于语法错误表未在数据库中创建

java - 访问类类型动态已知的对象的方法和函数

java动态选择要执行的类

java - 为什么Java代码需要编译而JavaScript代码不需要

java - 这是生成哈希码的好方法吗?