现在的位置: 首页 > 综合 > 正文

nutch配置到MyEclipse中出现org.apache.nutch.plugin.PluginRuntimeException

2014年02月15日 ⁄ 综合 ⁄ 共 3887字 ⁄ 字号 评论关闭

想把nutch-1.2的源码加载到MyEclipse中,所有的文件都加载成功了,而且在MyEclipse中也没有错误,然后运行Crawl.java类出现了下面的错误。

org.apache.nutch.plugin.PluginRuntimeException: java.lang.ClassNotFoundException: org.apache.nutch.net.urlnormalizer.basic.BasicURLNormalizer
	at org.apache.nutch.plugin.Extension.getExtensionInstance(Extension.java:170)
	at org.apache.nutch.net.URLNormalizers.getURLNormalizers(URLNormalizers.java:172)
	at org.apache.nutch.net.URLNormalizers.<init>(URLNormalizers.java:128)
	at org.apache.nutch.crawl.Injector$InjectMapper.configure(Injector.java:70)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:88)
	at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:64)
	at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:117)
	at org.apache.hadoop.mapred.MapRunner.configure(MapRunner.java:34)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:88)
	at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:64)
	at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:117)
	at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:354)
	at org.apache.hadoop.mapred.MapTask.run(MapTask.java:307)
	at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:177)

通过跟踪代码发现:是因为Extension类中getExtensionInstance()方法的Class extensionClazz = loader.loadClass(getClazz());这条语句出现了错误。这是一句很标准的使用ClassLoader加载类实例的语句,他不会出现错误,只能是被加载的插件出现了错误。

通过学习ClassLoader使用方法知道,被加载的类必须被编译成为.class的文件才可以,我的plugin目录下的所有类都还没有编译所以出现了上面的错误,通过将plugin中的所有类编译成.class类之后,再运行上面的代码问题就得到了解决。

下面是ClassLoader的使用方法:

一般的class都是由系统类加载器、或者其父加载器或者bootstartup加载器加载的,但在应用中可以指定类的加载器,然后将生成的class对象造型为具体的类。
    
 
public class LoadClass {
 
 public static void main(String args[]) throws MalformedURLException, ClassNotFoundException, InstantiationException, IllegalAccessException{
  URL url=new URL("file:/G:/test/");
  URLClassLoader loader=new URLClassLoader(new URL[]{url});
  Class c=loader.loadClass("LoadModel");
  Object o=c.newInstance();
  Comparable comparable=(Comparable)o;
  System.out.println("result:"+comparable.compareTo(""));
  }
}
 class LoadModel implements Comparable{
       public int compareTo(Object o){
              return 33;
      }
}
 
 
      以上的LoadModel类的class文件放置在G:/test/目录中(必须把LoadModel.java编译成class文件),而LoadClass.java放置在其他文件夹(避免通一个classpath,否则使用loader动态装载就没效用了).以上代码执行时可以获取结果。
      注意:不同的加载器即使加载的是同一个类,在jvm看来他们也是不同的类,不能进行转换。例如上面例子使用一个新的URLClassLoader动态加载了一个LoadModel实例(先使用newInstance()方法生成一个Object对象,其实该对象的类型是LoadModel),假设LoadModel在当前的类路径,即在G:/test/下有LoadModel.java文件,当使用LoadModel m=(LoadModel)o 进行强制转换时会出现ClassCastException异常,原因就是这两个LoadModel类型不在同一个ClassLoader中。要想使程序能运行,则须设定LoadModel基础一个当前类路径上的类或实现当前类路径上的一个接口,然后转换类型的时候把该类强制转换为其父类或其实现的接口就可以了,如上例(假如继承的类或实现的接口不是核心API里面的,那还必须在该类的classpath中定义该类的父类或其实现的接口),之所以可以这样是因为该类实现的接口或者继承的父类都是由同一个类加载器加载的(系统类加载器)。
      以上所说的可以概况为,两个类进行转换的的必要条件是他们都是由同一个类加载器加载,当我们的目标类实现了java核心API中的接口或者继承了核心API的类时,因为继承的接口和类只能在系统类加载器或扩展加载器又或者是bootstartup类加载器之一加载。我们的测试类肯定是由这三者之一加载了,根据类加载的全盘负责原则,测试类中的所有类也由测试类的加载器加载(除非显式的使用类加载器加载),这样可以确定了在测试类中出现的目标类接口(或者父类)是由系统加载器加载;另外我们测试类中显式的使用类加载器加载的目标类是由我们自定义的类加载器加载,而在目标类出现的目标类接口(或父类)也由我们自定义的类加载器加载,但根据类加载原则,自定义加载器会委托父加载器加载目标接口,这样,目标接口(或父类)就变成了使用系统类加载器加载了,这样测试类的目标接口(父类)与目标类所在文件的目标接口(父类)都由系统类加载器加载,从而他们也就可以相互转换了。
     
 
      另外必须把LoadModel.java编译成class文件的原因是,javac命令只能编译当前类路径的java文件,而LoadModel.java并不在当前classpath中。ClassLoader中的loadClass方法并不能编译java文件为class文件,它只是将.class文件载入内存而已。

抱歉!评论已关闭.