使用Java中的Reflection加载导入的已加载类的类

时间:2017-05-19 19:46:47

标签: java exception reflection

我正在尝试从jar文件加载类。基本上,我想在该jar的包中调用特定类中的方法。我在这里遇到的问题是,从jar成功加载类后,当我尝试实例化时,我得到异常:ClassNotFound用于在我的类中导入的类。

这是加载类的类:

输入:D:\ Myjar.jar,com.vendor.epbroker.VNFLCMCommunicator

public Class<?> loadClass(String libPath, String pkgName) {
        LogManager.getLogger().info("Adding Class");

        File jarFile = null;
        try {
            jarFile = new File(libPath);
            URL fileURL = jarFile.toURI().toURL();
            String jarURL = "jar:" + fileURL + "!/";
            URL urls[] = { new URL(jarURL) };
            URLClassLoader ucl = new URLClassLoader(urls);
            Class<?> beanClass = ucl.loadClass(pkgName);
            ucl.close();

            return beanClass;
        } catch (Exception ex) {
            LogManager.getLogger().error("Given Library: " + libPath + " or Class name: " + pkgName + " is not Valid");
            LogManager.getLogger().error("Exception occurred : ", ex);
        }

        LogManager.getLogger().error("Class loading Error: Returning NULL");
        return null;
    }

接收此类的代码段:

Object instance = classToLoad.newInstance();

                // To get the list of methods exist in the Class
Method[] listOfMethods = classToLoad.getMethods();

遇到以下错误:

SEVERE: Servlet.service() for servlet [spring] in context with path [/vnflcm] threw exception [Handler processing failed; nested exception is java.lang.NoClassDefFoundError: com/vendor/epbroker/exception/EPBrokerException] with root cause
java.lang.ClassNotFoundException: com.vendor.epbroker.exception.EPBrokerException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)

任何帮助都会受到赞赏吗?

2 个答案:

答案 0 :(得分:0)

尝试使用Reflection时,您需要考虑一些因素。

  1. 您的URLClassLoader必须包含您要反映的jar的URL。
  2. 如果所需的jar依赖于任何其他jar,您还必须加载这些jar的URL。
  3. 正如@VGR指出的那样,你不能简单地使用jar的文件路径作为URL。你可以做的一件事是:

     File myJar = new File("path/to/myJar.jar");
     URL myJarUrl = myJar.toURI().toURL();
    
  4. 一个证明问题的简单示例:

    让我们调用你的jar myToolProject。让我们说开发这个工具时你创建了一个类,称之为JsonMaker,它将POJO转换为JSON,然后通过gson.jar完成。当你构建你的jar时,我们称之为myjar.jar,你在清单中提到它依赖于gson。

    当试图反思myjar时,你会反思你的jar中的每个类,直到你到达JsonMaker.class。在尝试反映此处时,我们注意到此处存在com.google.Gson类型对象。 URLClassLoader查看其数组中的URLS并尝试在某个类中查找com.google.Gson。如果找不到任何com.google.Gson类,则无法反映该类,并抛出ClassNotFoundException

答案 1 :(得分:0)

看看以下几行:

URLClassLoader ucl = new URLClassLoader(urls);
Class<?> beanClass = ucl.loadClass(pkgName);
ucl.close();

并考虑URLClassLoader.close()的文档:

  

关闭此URLClassLoader,以便它不再可用于加载此加载程序定义的新类或资源。

换句话说,如果你真的使用了那个加载器的类,你应该只关闭一个类加载器。即使此时已经加载了所有必需的类,仍然可能需要访问所需的资源。请注意,某些框架有自己的反射库,需要访问类的字节代码,这些代码将像资源一样进行访问。

在您的具体情况下,它甚至更简单。您刚刚加载了一个类,它只触发了所需的最小类集(例如直接超类)的解析,但没有其他依赖项。然后关闭类加载器,防止后续加载jar文件中的任何其他类,当解析构造函数需要解析更多引用的类时,这会打击你。