简体   繁体   English

使用 URLClassLoader 加载 .class 文件

[英]Using URLClassLoader to load .class file

I'm aware that this question has been asked before:我知道之前有人问过这个问题:

How to use URLClassLoader to load a *.class file? 如何使用 URLClassLoader 加载 *.class 文件?

However I don't really understand due to the lack of example.但是,由于缺乏示例,我真的不明白。 I'm currently working on a project and trying to load user-given .class objects which can be located in any directories on the machine.我目前正在处理一个项目并尝试加载用户给定的 .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);

The last line gave me a ClassNotFoundException, from my experiment & understanding the user-given class function has to be in the classpath?最后一行给了我一个 ClassNotFoundException,从我的实验和理解用户给定的类函数必须在类路径中?

PS: 1st time posting questions feel free to correct me where I did not follow the appropriate manner. PS:第一次发布问题请随时纠正我没有遵循适当方式的地方。

//SOLUTION //解决方案

The solution that I arrived at with the generous help of [WillShackleford][1], this solution can load the a .class file in a given filepath.我在 [WillShackleford][1] 的慷慨帮助下得出的解决方案,该解决方案可以在给定的文件路径中加载 .class 文件。 For more information refer to code and their given comments.有关更多信息,请参阅代码及其给定的注释。

//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);
    }

In the directory /home/shackle/somedir/classes/pkg I have a file Test.class created from a java file with package pkg;/home/shackle/somedir/classes/pkg我有一个文件 Test.class 从一个带有package pkg;的 java 文件创建package pkg; eg :例如:

package pkg;

public class Test {

    public String toString() {
        return "secret_string";
    }
}

Then I load it with :然后我加载它:

System.out.println(new URLClassLoader(
        new URL[]{new File("/home/shackle/somedir/classes").toURI().toURL()}
).loadClass("pkg.Test").newInstance().toString());

Notice that I do not put the pkg/Test in the URL string but the load class argument has the pkg.请注意,我没有将 pkg/Test 放在 URL 字符串中,但加载类参数具有 pkg​​。 prefix.字首。

You can get the class name directly from the file like this:您可以直接从文件中获取类名,如下所示:

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);

An alternative that doesn't require access to internal 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 can then be loaded with:然后可以加载类:

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());

Your _sHashFunctionFilePath needs to have the package name of the target class removed from it, so the ClassLoader will look in _sHashFunctionFilePath + package.name + HashFunction.class as the path to the file._sHashFunctionFilePath需要有从它去掉了目标类的包名,这样的ClassLoader会看_sHashFunctionFilePath + package.name + HashFunction.class的文件路径。 If you don't do that, the ClassLoader won't be able to find the file.如果不这样做,ClassLoader 将无法找到该文件。

So if the target class is my.great.HashFunction in HashFunction.class , then it needs to be in a directory called my/great/ if you want to use URLClassLoader.因此,如果目标类是my.great.HashFunctionHashFunction.class ,那么它需要在一个名为目录my/great/如果你想使用的URLClassLoader。 Then, you'd use /path/to as the file:/// URL for your URLClassLoader if the .class file was actually found in /path/to/my/great/HashFunction.class .然后,如果 .class 文件实际上是在/path/to/my/great/HashFunction.class找到的,那么您将使用/path/to作为 URLClassLoader 的file:/// URL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM