【问题标题】:ClassNotFoundException while loading a class from file with URLClassLoader使用 URLClassLoader 从文件加载类时发生 ClassNotFoundException
【发布时间】:2014-09-01 09:00:24
【问题描述】:

我正在使用以下代码创建一个实现Target 接口的OdbcIniTarget 类的实例。 OdbcIniTarget 类已存在于应用程序中,但位于不同的包中,现在应该从不在类路径中的 target 目录加载。

...
// directory below is resolved to /D:/Workspace/<myproject>/targets/
private File targetsLocation = new File("targets");
...
private void loadTargets() {            

    URL url = null;
    try {
        url = targetsLocation.toURI().toURL();            
    } catch (MalformedURLException e) {

    }

    URL[] urls = new URL[]{ url };        
    URLClassLoader classLoader = new URLClassLoader(urls);

    try {

     Target target =
     (Target)classLoader.
     loadClass("ch.blah.targets.nope.OdbcIniTarget").
     newInstance(); // <--- this fails hard  

    } catch (...) {
     ...
    }            

    try {
        classLoader.close();
    } catch (IOException e) {

    }
}

我收到以下异常。

java.lang.ClassNotFoundException: ch.blah.targets.nope.OdbcIniTarget
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at ch.blah.targets.TargetFactory.loadTargets(TargetFactory.java:74)
    at ch.blah.targets.TargetFactory.<init>(TargetFactory.java:41)
    at ch.blah.SomeOfMyClasses.<init>(SomeOfMyClasses.java:34)
    at ch.blah.TheMainClass.main(TheMainClass.java:38)

有人知道为什么找不到该类吗?

加载的类如下所示。

package ch.blah.targets.nope;

import org.apache.log4j.Logger;

import ch.blah.utils.Utils;

public class OdbcIniTarget extends Target {

    private static final Logger log = Logger.getLogger(OdbcIniTarget.class);    

    @Override
    public boolean someMethod1() {
        return false;
    }

    @Override
    public boolean someMethod2() {
        return false;
    }

    @Override
    public boolean someMethod3() {
        return false;
    }       

    @Override
    public void someMethod4() {
        log.debug("Blah.");
        Utils.getInstance().marshalClass(SomeClass.class);
        log.debug("Finished.");
    }
}

targets目录的目录结构如下。

D:\Workspace\<myproject>\targets>dir
 Volume in drive D is DATA
 Volume Serial Number is 021C-EC9B

 Directory of D:\Workspace\<myproject>\targets

10.07.2014  21:20    <DIR>          .
10.07.2014  21:20    <DIR>          ..
10.07.2014  21:31             1'278 OdbcIniTarget.java
10.07.2014  20:23             3'761 OdbcIniTargetConfiguration.java
               2 File(s)          5'039 bytes
               2 Dir(s)   7'328'571'392 bytes free

【问题讨论】:

  • /D:/Workspace/&lt;myproject&gt;/targets/ 的树目录结构是什么?
  • 我在问题的末尾添加了树结构。

标签: java reflection urlclassloader


【解决方案1】:

问题:

加载失败,因为它不包含该 URL 的类,它有 java 源

解决方案:

将这些 java 类编译为 .class 文件,然后将 url 传递到应该看起来像这样的目录

ch\blah\targets\nope\OdbcIniTarget.class

【讨论】:

  • 请不要告诉我用java不能及时编译?!
  • 即时编译与源代码编译不同,如果您想在运行时将 java 编译为类,您可以使用编译器 API stackoverflow.com/questions/1064259/…
  • 但我想知道你想达到什么目的,为什么你不能在执行它们之前编译?
  • 我想将经常更改并作为 Java 源代码放置在文件系统中的模块(想想插件)加载到主应用程序中,而不必重新编译整个应用程序。
【解决方案2】:

尝试在构造函数中将调用者的类加载器作为参数传递:

URLClassLoader classLoader = new URLClassLoader(urls, getClass().class.getClassLoader());

该类是 url 中目录的直接子级,因此您不需要包:

Target target =
 (Target)classLoader.
 loadClass("OdbcIniTarget").
 newInstance();

【讨论】:

  • 不,这也失败了。我也尝试过设置Thread.currentThread().setContextClassLoader(classLoader);,但仍然失败。
猜你喜欢
  • 1970-01-01
  • 2015-12-22
  • 1970-01-01
  • 1970-01-01
  • 2015-06-23
  • 1970-01-01
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多