在Nutch中,大量的可扩展的部分都使用了插件来做,如网页下载时所用的协议选择,解析不同类型的网页,url的过滤和规范化都使用了Nutch的插件机制。
Nutch中插件的主要目标是:
- 可扩展性:用户可以通过实现相应的接口来生成自己的扩展插件
- 灵活性:任务人都可以参与插件的编写。
- 可维护性:插件的开发者只要实现相应的扩展接口,而不需要关注插件的内部原理。
下面对其原理和代码做一个简单的分析。
1. 一些概念
1.1 插件仓库(PluginRepository)
插件仓库是一个所有插件的注册器,在系统启动时,这个仓库是通过分析插件目录中所有插件的mainfest文件来生成。对于每一个插件都会生成一个插件描述实例,它包含了每一个插件的元数据,所以插件的真正的实例会在用的时候再来创建,也就是所谓的延迟插件载入机制(lazy plugin loading)。
1.2 插件(Plugin)
Nutch中的插件实际上是一系列自定义逻辑的容器,而这些自定义逻辑为Nutch的核心功能提供扩展和为其它插件提供扩展API。一个插件要提供一个或者一组扩展。而对于扩展点来说(ExtensionPoints)来说,这些扩展都可以被看做是一组可以被动态加载的监听器。每一个具体的插件都扩展自基类Plugin,而这些实例又被用于去管理相关功能的生命周期。插件打开与关闭都由Nutch的插件管理系统来操作。
1.3 扩展(Extension)
扩展相当于一种被安装在具体的扩展点(ExtensionPoint)上的监听描述符,这里的扩展点扮演了一个发布者的角色。
1.4 扩展点(ExtensionPoint)
扩展点提供了一类具体功能扩展的元信息,它包含了具体的扩展。
1.5 插件描述符(PluginDescriptor)
插件描述符提供了一种对于Nutch所插件元数据的一种描述,它包含了国际化资源和插件本自的classloader。而这些元数据包含了插件(Plugin)、插件扩展点(ExtensionPoint)和扩展(Extension).而这里为了能够通过插件描述符来管理元数据,提供了一种延迟加载机制。
2. 使用bin/nutch运行插件
本机运行出现的帮助
-
lemo@debian:~/Workspace/java/Apache/Nutch/nutch-1.3$ bin/nutch plugin
-
Usage: PluginRepository pluginId className [arg1 arg2 ...]
这里主要有三个参数:
- pluginId:这个是插件的id号,它是每一个插件目录中的plugin.xml文件里里面plugin标签中的id属性
- className:这是扩展插件的类全
- args:这是插件main函数的参数
一个简单的调用protocoal的Http协议的命令:
-
bin/nutch plugin protocol-http org.apache.nutch.protocol.http.Http -verbose -timeout 10 http://www.baidu.com
- pluginId: protocol-http
- className: org.apache.nutch.protocol.http.Http
- args: -verbos -timeout 10 http://www.baidu.com
这里的输出就是baidu的网页源代码。
下面简单分析一下其调用的源代码。
3. 源代码分析
这是PluginRepository.java中的main函数,上面的bin/nutch plugin命令就是调用这个函数的
-
public static void main(String[] args) throws Exception {
-
if (args.length < 2) {
-
System.err
-
.println("Usage: PluginRepository pluginId className [arg1 arg2 ...]");
-
return;
-
}
-
// 生成Nutch的配置
-
// 这里主要使用的参数是plugin的目录名,还有plugin.includes包含哪些要读取的plugin
-
Configuration conf = NutchConfiguration.create();
-
// 根据配置生成一个插件仓库,并且对其进行初始化
-
PluginRepository repo = new PluginRepository(conf);
-
// args[0] - plugin ID
-
// 根据插件ID得到特定的插件描述符
-
PluginDescriptor d = repo.getPluginDescriptor(args[0]);
-
if (d == null) {
-
System.err.println("Plugin '" + args[0] + "' not present or inactive.");
-
return;
-
}
-
// 从插件描述符对象中得到类加载器
-
ClassLoader cl = d.getClassLoader();
-
// args[1] - class name
-
Class clazz = null;
-
try {
-
// 加载对应的类
-
clazz = Class.forName(args[1], true, cl);
-
} catch (Exception e) {
-
System.err.println("Could not load the class '" + args[1] + ": "
-
+ e.getMessage());
-
return;
-
}
-
Method m = null;
-
try {
-
// 得到特定的main方法
-
m = clazz.getMethod("main", new Class[] { args.getClass() });
-
} catch (Exception e) {
-
System.err.println("Could not find the 'main(String[])' method in class "
-
+ args[1] + ": " + e.getMessage());
-
return;
-
}
-
String[] subargs = new String[args.length - 2];
-
System.arraycopy(args, 2, subargs, 0, subargs.length);
-
// 这里是运行插件的main方法
-
m.invoke(null, new Object[] { subargs });
-
}
4. 总结
这里只是对Nutch的插件做一个简单的介绍,下面我们会来自己动手写一个相应的插件,最后我们会看一下其插件的实现原理。
5. 参考
http://wiki.apache.org/nutch/PluginCentral?highlight=%28%28WhichTechnicalConceptsAreBehindTheNutchPluginSystem%29%29
http://www.mikkoo.info/?p=101
http://hi.baidu.com/bupo_jung/blog/item/0603dcd871af2e2033fa1cd5.html
作者:http://blog.csdn.net/amuseme_lu
相关文章阅读及免费下载:
《Apache Nutch 1.3 学习笔记三(Inject)》
《Apache Nutch 1.3 学习笔记三(Inject CrawlDB Reader)》
《Apache Nutch 1.3 学习笔记四(Generate)》
《Apache Nutch 1.3 学习笔记四(SegmentReader分析)》
《Apache Nutch 1.3 学习笔记五(FetchThread)》
《Apache Nutch 1.3 学习笔记五(Fetcher流程)》
《Apache Nutch 1.3 学习笔记六(ParseSegment)》
《Apache Nutch 1.3 学习笔记七(CrawlDb - updatedb)》
《Apache Nutch 1.3 学习笔记八(LinkDb)》
《Apache Nutch 1.3 学习笔记九(SolrIndexer)》
《Apache Nutch 1.3 学习笔记十(Ntuch 插件机制简单介绍)》
《Apache Nutch 1.3 学习笔记十(插件扩展)》
《Apache Nutch 1.3 学习笔记十(插件机制分析)》
《Apache Nutch 1.3 学习笔记十一(页面评分机制 OPIC)》
《Apache Nutch 1.3 学习笔记十一(页面评分机制 LinkRank 介绍)》