Nutch 1.3 学习笔记 10 -1 - Ntuch 插件机制简单介绍
----------------------------------------
在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