使用 URLClassLoader 加载 .class 文件
Using URLClassLoader to load .class file
我知道之前有人问过这个问题:
How to use URLClassLoader to load a *.class file?
但是由于缺乏例子,我不是很明白。我目前正在处理一个项目并尝试加载用户给定的 .class 对象,这些对象可以位于机器上的任何目录中。
//Create URL to hash function class file
URL url_hashFunctionPath = new URL("file:///" + _sHashFunctionFilePath);
//Packet URL to a URL array to be used by URLClassLoader
URL[] urlA_hashFunctionPath = {url_hashFunctionPath};
//Load URL for hash function via a URL class loader
URLClassLoader urlCl_hashFunctionClassLoader = new URLClassLoader(urlA_hashFunctionPath);
//Load user hash function into class to initialize later (TEST: HARD CODE FOR NOW)
m_classUserHashClass = urlCl_hashFunctionClassLoader.loadClass(_sUserHashClassName);
最后一行给了我一个 ClassNotFoundException,根据我的实验和理解用户给定的 class 函数必须在 class 路径中?
PS: 第一次发帖,有不当的地方欢迎指正。
//解决方案
我在 [WillShackleford][1] 的慷慨帮助下得出的解决方案,该解决方案可以加载给定文件路径中的 .class 文件。有关更多信息,请参阅代码及其给出的注释。
//The absolute file path to the class that is to be loaded (_sHashFunctionFilePath = absolute file path)
String pathToClassFile = _sHashFunctionFilePath;
System.out.println("File to class: " + _sHashFunctionFilePath);
//Declare the process builder to execute class file at run time (Provided filepath to class)
ProcessBuilder pb = new ProcessBuilder("javap", pathToClassFile);
try
{
//Start the process builder
Process p = pb.start();
//Declare string to hold class name
String classname = null;
//Declare buffer reader to read the class file & get class name
try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())))
{
String line;
while(null != (line = br.readLine()))
{
if(line.startsWith("public class"))
{
classname = line.split(" ")[2];
break;
}
}
System.out.println("classname = " + classname);
}
catch(IOException _error)
{
}
//Declare file path to directory containing class to be loaded
String pathToPackageBase = pathToClassFile.substring(0, pathToClassFile.length() - (classname + ".class").length());
System.out.println("pathToPackageBase = " + pathToPackageBase);
try
{
//Create class to hold the class to be loaded via a URL class loader
Class clss = new URLClassLoader(
new URL[]{new File(pathToPackageBase).toURI().toURL()}
).loadClass(classname);
//Create ab object/instance of said class
Object test = clss.newInstance();
//Declare & create requested method from user hash function class (Method is work & takes no arguments)
Method method = clss.getMethod("work", null);
method.invoke(test, null);
}
在目录 /home/shackle/somedir/classes/pkg
中,我有一个文件 Test.class 从 java 文件创建 package pkg;
例如:
package pkg;
public class Test {
public String toString() {
return "secret_string";
}
}
然后我加载它:
System.out.println(new URLClassLoader(
new URL[]{new File("/home/shackle/somedir/classes").toURI().toURL()}
).loadClass("pkg.Test").newInstance().toString());
请注意,我没有将 pkg/Test 放在 URL 字符串中,但加载 class 参数包含 pkg。前缀。
您可以像这样直接从文件中获取 class 名称:
Class clsReaderClss = ClassLoader.getSystemClassLoader().loadClass("jdk.internal.org.objectweb.asm.ClassReader");
System.out.println("clsReaderClss = " + clsReaderClss);
Constructor con = clsReaderClss.getConstructor(InputStream.class);
Object reader = con.newInstance(new FileInputStream(directFile));
Method m = clsReaderClss.getMethod("getClassName");
String name = m.invoke(reader).toString().replace('/', '.');
System.out.println("name = " + name);
不需要访问内部 classes 的替代方案。
String pathToClassFile = "/home/shackle/somedir/classes/pkg/Test.class";
ProcessBuilder pb = new ProcessBuilder("javap",pathToClassFile);
Process p = pb.start();
String classname = null;
try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while(null != (line = br.readLine())) {
if(line.startsWith("public class")) {
classname = line.split(" ")[2];
break;
}
}
}
System.out.println("classname = " + classname);
Class 然后可以加载:
String pathToPackageBase = pathToClassFile.substring(0, pathToClassFile.length() - (classname + ".class").length());
System.out.println("pathToPackagBase = " + pathToPackageBase);
Class clss = new URLClassLoader(
new URL[]{new File(pathToPackageBase).toURI().toURL()}
).loadClass(classname);
System.out.println(clss.newInstance().toString());
您的 _sHashFunctionFilePath
需要从中删除目标 class 的包名称,因此类加载器将查找 _sHashFunctionFilePath
+ package.name
+ HashFunction.class
作为文件的路径。如果不这样做,ClassLoader 将无法找到该文件。
因此,如果目标 class 是 HashFunction.class
中的 my.great.HashFunction
,那么如果您想使用 URL,则它需要位于名为 my/great/
的目录中]类加载器。然后,如果 .class 文件实际在 /path/to/my/great/HashFunction.class
中找到,您将使用 /path/to
作为 URLClassLoader 的 file:///
URL。
我知道之前有人问过这个问题:
How to use URLClassLoader to load a *.class file?
但是由于缺乏例子,我不是很明白。我目前正在处理一个项目并尝试加载用户给定的 .class 对象,这些对象可以位于机器上的任何目录中。
//Create URL to hash function class file
URL url_hashFunctionPath = new URL("file:///" + _sHashFunctionFilePath);
//Packet URL to a URL array to be used by URLClassLoader
URL[] urlA_hashFunctionPath = {url_hashFunctionPath};
//Load URL for hash function via a URL class loader
URLClassLoader urlCl_hashFunctionClassLoader = new URLClassLoader(urlA_hashFunctionPath);
//Load user hash function into class to initialize later (TEST: HARD CODE FOR NOW)
m_classUserHashClass = urlCl_hashFunctionClassLoader.loadClass(_sUserHashClassName);
最后一行给了我一个 ClassNotFoundException,根据我的实验和理解用户给定的 class 函数必须在 class 路径中?
PS: 第一次发帖,有不当的地方欢迎指正。
//解决方案
我在 [WillShackleford][1] 的慷慨帮助下得出的解决方案,该解决方案可以加载给定文件路径中的 .class 文件。有关更多信息,请参阅代码及其给出的注释。
//The absolute file path to the class that is to be loaded (_sHashFunctionFilePath = absolute file path)
String pathToClassFile = _sHashFunctionFilePath;
System.out.println("File to class: " + _sHashFunctionFilePath);
//Declare the process builder to execute class file at run time (Provided filepath to class)
ProcessBuilder pb = new ProcessBuilder("javap", pathToClassFile);
try
{
//Start the process builder
Process p = pb.start();
//Declare string to hold class name
String classname = null;
//Declare buffer reader to read the class file & get class name
try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())))
{
String line;
while(null != (line = br.readLine()))
{
if(line.startsWith("public class"))
{
classname = line.split(" ")[2];
break;
}
}
System.out.println("classname = " + classname);
}
catch(IOException _error)
{
}
//Declare file path to directory containing class to be loaded
String pathToPackageBase = pathToClassFile.substring(0, pathToClassFile.length() - (classname + ".class").length());
System.out.println("pathToPackageBase = " + pathToPackageBase);
try
{
//Create class to hold the class to be loaded via a URL class loader
Class clss = new URLClassLoader(
new URL[]{new File(pathToPackageBase).toURI().toURL()}
).loadClass(classname);
//Create ab object/instance of said class
Object test = clss.newInstance();
//Declare & create requested method from user hash function class (Method is work & takes no arguments)
Method method = clss.getMethod("work", null);
method.invoke(test, null);
}
在目录 /home/shackle/somedir/classes/pkg
中,我有一个文件 Test.class 从 java 文件创建 package pkg;
例如:
package pkg;
public class Test {
public String toString() {
return "secret_string";
}
}
然后我加载它:
System.out.println(new URLClassLoader(
new URL[]{new File("/home/shackle/somedir/classes").toURI().toURL()}
).loadClass("pkg.Test").newInstance().toString());
请注意,我没有将 pkg/Test 放在 URL 字符串中,但加载 class 参数包含 pkg。前缀。
您可以像这样直接从文件中获取 class 名称:
Class clsReaderClss = ClassLoader.getSystemClassLoader().loadClass("jdk.internal.org.objectweb.asm.ClassReader");
System.out.println("clsReaderClss = " + clsReaderClss);
Constructor con = clsReaderClss.getConstructor(InputStream.class);
Object reader = con.newInstance(new FileInputStream(directFile));
Method m = clsReaderClss.getMethod("getClassName");
String name = m.invoke(reader).toString().replace('/', '.');
System.out.println("name = " + name);
不需要访问内部 classes 的替代方案。
String pathToClassFile = "/home/shackle/somedir/classes/pkg/Test.class";
ProcessBuilder pb = new ProcessBuilder("javap",pathToClassFile);
Process p = pb.start();
String classname = null;
try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
String line;
while(null != (line = br.readLine())) {
if(line.startsWith("public class")) {
classname = line.split(" ")[2];
break;
}
}
}
System.out.println("classname = " + classname);
Class 然后可以加载:
String pathToPackageBase = pathToClassFile.substring(0, pathToClassFile.length() - (classname + ".class").length());
System.out.println("pathToPackagBase = " + pathToPackageBase);
Class clss = new URLClassLoader(
new URL[]{new File(pathToPackageBase).toURI().toURL()}
).loadClass(classname);
System.out.println(clss.newInstance().toString());
您的 _sHashFunctionFilePath
需要从中删除目标 class 的包名称,因此类加载器将查找 _sHashFunctionFilePath
+ package.name
+ HashFunction.class
作为文件的路径。如果不这样做,ClassLoader 将无法找到该文件。
因此,如果目标 class 是 HashFunction.class
中的 my.great.HashFunction
,那么如果您想使用 URL,则它需要位于名为 my/great/
的目录中]类加载器。然后,如果 .class 文件实际在 /path/to/my/great/HashFunction.class
中找到,您将使用 /path/to
作为 URLClassLoader 的 file:///
URL。