是否可以强制其他人的 java ClassLoader 加载包含有效 Java class 字节码的外部字节数组?
Is it possible to force someone else's java ClassLoader to load an external byte array containing the bytecode of a valid Java class?
我正在尝试强制系统 java class 加载程序(即 ClassLoader.getSystemClassLoader()
)加载由具有有效字节码的字节数组定义的外部 class 所以随后由此 classloader 加载的其他 classes 可以知道并实例化外部 class 而无需获得 NoClassDefFoundError
.
这肯定行不通,因为它只在创建的 classloader 上定义了 class,而不是在系统 classloader:
中
URLClassLoader child =
new URLClassLoader(new URL[] { myJar.toURI().toURL()
, ClassLoader.getSystemClassLoader());
Class.forName ("com.MyClass", true, child);
上面的代码将为子 classloader 定义 com.MyClass
,而不是系统 classloader。
有什么方法可以做到吗?
您可以将反射与访问覆盖一起使用:
Method define = ClassLoader.class.getDeclaredMethod("defineClass",
String.class, byte[].class, int.class, int.class);
define.setAccessible(true);
Class<?> clazz = (Class<?>)define.invoke(ClassLoader.getSystemClassLoader(),
null, array, 0, array.length);
访问覆盖是必需的,因为我们正在调用 a protected
method,但作为 protected
方法,它仍然是 API 的一部分,它存在于所有实现中并且不会'在未来的版本中不会消失。
Java 9 引入了一种惊人的简单方法,无需破解即可实现相同的效果,只要您自己的 class 也已通过应用程序 class 加载程序加载(以及是默认值):
Class<?> clazz = MethodHandles.lookup().defineClass(array);
这只是在与包含此语句的 class 相同的 class 加载上下文中创建 class。
我正在尝试强制系统 java class 加载程序(即 ClassLoader.getSystemClassLoader()
)加载由具有有效字节码的字节数组定义的外部 class 所以随后由此 classloader 加载的其他 classes 可以知道并实例化外部 class 而无需获得 NoClassDefFoundError
.
这肯定行不通,因为它只在创建的 classloader 上定义了 class,而不是在系统 classloader:
中URLClassLoader child =
new URLClassLoader(new URL[] { myJar.toURI().toURL()
, ClassLoader.getSystemClassLoader());
Class.forName ("com.MyClass", true, child);
上面的代码将为子 classloader 定义 com.MyClass
,而不是系统 classloader。
有什么方法可以做到吗?
您可以将反射与访问覆盖一起使用:
Method define = ClassLoader.class.getDeclaredMethod("defineClass",
String.class, byte[].class, int.class, int.class);
define.setAccessible(true);
Class<?> clazz = (Class<?>)define.invoke(ClassLoader.getSystemClassLoader(),
null, array, 0, array.length);
访问覆盖是必需的,因为我们正在调用 a protected
method,但作为 protected
方法,它仍然是 API 的一部分,它存在于所有实现中并且不会'在未来的版本中不会消失。
Java 9 引入了一种惊人的简单方法,无需破解即可实现相同的效果,只要您自己的 class 也已通过应用程序 class 加载程序加载(以及是默认值):
Class<?> clazz = MethodHandles.lookup().defineClass(array);
这只是在与包含此语句的 class 相同的 class 加载上下文中创建 class。