1. 一些对象说明

  1. PluginRepository:这是一个用于存储所有插件描述对象(PluginDescriptor),插件扩展点(ExtensionPoint)和被激活的插件。
  2. PluginDescriptor:用于描述单个扩展插件的元信息,它的内容主要是从plugin.xml中得到。
  3. Plugin: 用于描述插件的一个抽象,其中包括了一个插件描述符,它们是一对一的关系。
  4. ExtensionPoint: 这个扩展点主要是一个面象对象中的接口的意思,就是说可以有多个扩展来实现这个接口,一个或者多个扩展点实际上就是一个插件,如nutch-extensionpoints.
  5. Extension: 扩展是对于扩展点的实现,一个插件可以包含多个扩展。
  6. PluginManifestParser: 主要是用于解析插件目录下的plugin.xml文件,生成相应的PluginDescriptor对象。
  7. PluginClassLoader: 它继承自URLClassLoader,用来根据urls动态生成相应的插件实现对象

2. 插件仓库初始化流程

PluginRepository的生成有两种方法,一个是直接new一个相应的对象,另一个是调用PluginRepository的静态的get方法,从Cache中得到相应的PluginRepository,在Nutch的流程中,一般是通用使用第二种方法来得到PluginRepository,这样可以保证资源在多个流程中得到共享。

2.1 PluginRepostory的初始化在其ctr函数中进行

源代码如下:

  1. fActivatedPlugins = new HashMap<String, Plugin>();  
  2.         fExtensionPoints = new HashMap<String, ExtensionPoint>();  
  3.         this.conf = conf;  
  4.         // 当被配置为过滤(即不加载),但是又被其他插件依赖的时候,是否自动启动,缺省为 true  
  5.         this.auto = conf.getBoolean("plugin.auto-activation", true);  
  6.         // 插件的目录名,可以是多个目录  
  7.         String[] pluginFolders = conf.getStrings("plugin.folders");  
  8.         PluginManifestParser manifestParser = new PluginManifestParser(conf, this);  
  9.         Map<String, PluginDescriptor> allPlugins = manifestParser.parsePluginFolder(pluginFolders);  
  10.         // 要排除的插件名称列表,支持正则表达式方式定义  
  11.         Pattern excludes = Pattern.compile(conf.get("plugin.excludes", ""));  
  12.         // 要包含的插件名称列表,支持正则表达式方式定义  
  13.         Pattern includes = Pattern.compile(conf.get("plugin.includes", ""));  
  14.         // 对不使用的插件进行过滤,返回过滤后的插件  
  15.         Map<String, PluginDescriptor> filterfilteredPlugins = filter(excludes, includes,allPlugins);  
  16.         // 对插件的依赖关系进行检查  
  17.         fRegisteredPlugins = getDependencyCheckedPlugins(filteredPlugins,this.auto ? allPlugins : filteredPlugins);  
  18.         // 安装扩展点,主要是针对nutch-extensionpoints这个插件的  
  19.         installExtensionPoints(fRegisteredPlugins);  
  20.         try {  
  21.             // 安装特定扩展点的相应扩展集  
  22.             // NOTE:其实这边的扩展点与扩展都是以插件的形式表现的  
  23.             installExtensions(fRegisteredPlugins);  
  24.         } catch (PluginRuntimeException e) {  
  25.             LOG.fatal(e.toString());  
  26.             throw new RuntimeException(e.getMessage());  
  27.         }  
  28.         displayStatus();  

2.2 下面分析一个插件描述符的生成

插件描述符的生成主要是通用调用PluginManifestParser这个对象的parsePluginFolder这个方法生成的,源代码如下:

  1. /**  
  2.               * Returns a list of all found plugin descriptors.  
  3.               *   
  4.               * @param pluginFolders  
  5.               *          folders to search plugins from  
  6.               * @return A {@link Map} of all found {@link PluginDescriptor}s.  
  7.               */  
  8.             public Map<String, PluginDescriptor> parsePluginFolder(String[] pluginFolders) {  
  9.         Map<String, PluginDescriptor> map = new HashMap<String, PluginDescriptor>();  
  10.         if (pluginFolders == null) {  
  11.                 throw new IllegalArgumentException("plugin.folders is not defined");  
  12.         }  
  13.         for (String name : pluginFolders) {  
  14.             // 遍历所有插件目录,这里的getPluginFolder方法解析一个资源的相对路径的问题  
  15.                 File directory = getPluginFolder(name);  
  16.                 if (directory == null) {  
  17.                 continue;  
  18.                 }  
  19.             LOG.info("Plugins: looking in: " + directory.getAbsolutePath());  
  20.         // 遍历所有子插件目录中的插件  
  21.             for (File oneSubFolder : directory.listFiles()) {  
  22.             if (oneSubFolder.isDirectory()) {  
  23.                     String manifestPath = oneSubFolder.getAbsolutePath() + File.separator  
  24.                     + "plugin.xml";  
  25.                 try {  
  26.             LOG.debug("parsing: " + manifestPath);  
  27.             // 分析plugin.xml文件  
  28.             PluginDescriptor p = parseManifestFile(manifestPath);  
  29.             map.put(p.getPluginId(), p);  
  30.                 } catch (MalformedURLException e) {  
  31.             LOG.warn(e.toString());  
  32.             } catch (SAXException e) {  
  33.            LOG.warn(e.toString());  
  34.             } catch (IOException e) {  
  35.            LOG.warn(e.toString());  
  36.             } catch (ParserConfigurationException e) {  
  37.            LOG.warn(e.toString());  
  38.             }  
  39.         }  
  40.         }  
  41.     }  
  42.     return map;  
  43.     }  
  1. private PluginDescriptor parseManifestFile(String pManifestPath)  
  2.         throws MalformedURLException, SAXException, IOException,  
  3.         ParserConfigurationException {  
  4.     // 解析xml文件,生成Document对象  
  5.         Document document = parseXML(new File(pManifestPath).toURL());  
  6.         String pPath = new File(pManifestPath).getParent();  
  7. // 对xml进行分析  
  8.         return parsePlugin(document, pPath);  
  9.     }  
  1. private PluginDescriptor parsePlugin(Document pDocument, String pPath)  
  2.             throws MalformedURLException {  
  3.    Element rootElement = pDocument.getDocumentElement();  
  4. // 这里是解析xml中的如下信息  
  5. // <plugin id="index-anchor" name="Anchor Indexing Filter" version="1.0.0" provider-name="nutch.org">  
  6.    String id = rootElement.getAttribute(ATTR_ID);  
  7.    String name = rootElement.getAttribute(ATTR_NAME);  
  8.    String version = rootElement.getAttribute("version");  
  9.    String providerName = rootElement.getAttribute("provider-name");  
  10. // 插件类属性,不过这里好像没有用到过  
  11.    String pluginClazz = null;  
  12.    if (rootElement.getAttribute(ATTR_CLASS).trim().length() > 0) {  
  13.      pluginClazz = rootElement.getAttribute(ATTR_CLASS);  
  14.    }  
  15. // 生成插件描述符对象  
  16.    PluginDescriptor pluginDescriptor = new PluginDescriptor(id, version, name,  
  17.        providerName, pluginClazz, pPath, this.conf);  
  18.    LOG.debug("plugin: id=" + id + " name=" + name + " version=" + version  
  19.          + " provider=" + providerName + "class=" + pluginClazz);  
  20. // 这里是解析如下内容  
  21. //  <extension id="org.apache.nutch.indexer.anchor" name="Nutch Anchor Indexing Filter" point="org.apache.nutch.indexer.IndexingFilter">  
  22.    //   <implementation id="AnchorIndexingFilter"  
  23.    //       class="org.apache.nutch.indexer.anchor.AnchorIndexingFilter" />  
  24.     //  </extension>  
  25.    parseExtension(rootElement, pluginDescriptor);  
  26. // 这里主要是解析nutch-extensionPoints这个插件,xml内容如下  
  27. // <extension-point id="org.apache.nutch.indexer.IndexingFilter" name="Nutch Indexing Filter"/>  
  28.    // <extension-point id="org.apache.nutch.parse.Parser" name="Nutch Content Parser"/>  
  29.    // <extension-point id="org.apache.nutch.parse.HtmlParseFilter" name="HTML Parse Filter"/>  
  30.    parseExtensionPoints(rootElement, pluginDescriptor);  
  31. // 这里主要是解析插件的动态库与插件所使用的第三方库,xml内容如下  
  32. // <runtime>  
  33.    //  <library name="parse-tika.jar">  
  34.    //     <export name="*"/>  
  35.    //  </library>  
  36.    //  <library name="apache-mime4j-0.6.jar"/>  
  37.    //  <library name="asm-3.1.jar"/>  
  38.    //  <library name="bcmail-jdk15-1.45.jar"/>  
  39.    //  <library name="bcprov-jdk15-1.45.jar"/>  
  40. //  </runtime>  
  41.    parseLibraries(rootElement, pluginDescriptor);  
  42. // 这里解析插件依赖的插件库,xml内容如下  
  43. //  <requires>  
  44.    //   <import plugin="nutch-extensionpoints"/>  
  45.    //  <import plugin="lib-regex-filter"/>  
  46.    //  </requires>  
  47.    parseRequires(rootElement, pluginDescriptor);  
  48.    return pluginDescriptor;  
  49.  }  

要注意的是这个PluginManifestParser就是用来解析相应的plugin.xml文件,生成PluginRepository对象的,这个有一个很奇怪的概念就是一个插件描述符(PluginDescriptor)可以包含多个可扩展点或者可扩展点的实现,这里为什么不把可扩展点分离出来,PluginDescriptor就只包含一个或者多个可扩展点的实现。而可扩展点就是插件的接口定义。

2.3 插件依赖关系的检查
这个依赖关系的检查很有趣,主要是根据plugin.auto-activation这个参数来定的,部分源代码如下:

  1. /**  
  2.   * @param filtered  
  3.   *          is the list of plugin filtred  
  4.   * @param all  
  5.   *          is the list of all plugins found.  
  6.   * @return List  
  7.   */  
  8.  private List<PluginDescriptor> getDependencyCheckedPlugins(  
  9.      Map<String, PluginDescriptor> filtered, Map<String, PluginDescriptor> all) {  
  10.    if (filtered == null) {  
  11.      return null;  
  12.    }  
  13.    Map<String, PluginDescriptor> checked = new HashMap<String, PluginDescriptor>();  
  14. // 遍历所有过滤后的插件  
  15.    for (PluginDescriptor plugin : filtered.values()) {  
  16.      try {  
  17.       // 保存当前插件的依赖插件描述符  
  18.        checked.putAll(getPluginCheckedDependencies(plugin, all));  
  19.     // 保存当前插件描述符  
  20.        checked.put(plugin.getPluginId(), plugin);  
  21.      } catch (MissingDependencyException mde) {  
  22.        // Log exception and ignore plugin  
  23.        LOG.warn(mde.getMessage());  
  24.      } catch (CircularDependencyException cde) {  
  25.   // Simply ignore this plugin  
  26.        LOG.warn(cde.getMessage());  
  27.      }  
  28.    }  
  29.    return new ArrayList<PluginDescriptor>(checked.values());  
  30.  }  

3. 插件调用流程
  插件调用流程主要分成如下几步:

  1. 根据扩展点ID号从插件仓库中得到相应的扩展点对象
  2. 根据扩展点对象得到相应的扩展集
  3. 遍历扩展集,从扩展对象中实例化出相应的扩展来,实例化的过滤就是调用PluginClassLoader

下面是生成URLFilter插件的部分代码:

  1.    (1)  
  2. ExtensionPoint point = PluginRepository.get(conf).getExtensionPoint(URLFilter.X_POINT_ID);  
  3. if (point == null)  
  4.   throw new RuntimeException(URLFilter.X_POINT_ID + " not found.");  
  5.    (2)  
  6. Extension[] extensions = point.getExtensions();  
  7. Map<String, URLFilter> filterMap = new HashMap<String, URLFilter>();  
  8. for (int i = 0; i < extensions.length; i++) {  
  9.   Extension extension = extensions[i];  
  10.    (3)  
  11.   URLFilter filter = (URLFilter) extension.getExtensionInstance();  
  12.   if (!filterMap.containsKey(filter.getClass().getName())) {  
  13.     filterMap.put(filter.getClass().getName(), filter);  
  14.   }  
  15. }  

4. 总结

Nutch的插件机制还是比较经典的,上面只是做了一个简单的分析,要深入理解还是要多实践。

作者:http://blog.csdn.net/amuseme_lu


相关文章阅读及免费下载:

Apache Nutch 1.3 学习笔记目录

Apache Nutch 1.3 学习笔记一

Apache Nutch 1.3 学习笔记二

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 介绍)

Apache Nutch 1.3 学习笔记十二(Nutch 2.0 的主要变化)

更多《Apache Nutch文档》,尽在开卷有益360 http://www.docin.com/book_360

转载于:https://www.cnblogs.com/ibook360/archive/2011/10/24/2222179.html

Apache Nutch 1.3 学习笔记十(插件机制分析)相关推荐

  1. Apache Nutch 1.3 学习笔记十一(页面评分机制 OPIC)

    1. Nutch 1.3 的页面评分机制 Nutch1.3目前默认还是使用OPIC作为其网页分数算法,但其之后,已经引入了PageRank-like算法,以弥补OPIC算法的不足,目前OPIC算法还是 ...

  2. Apache Nutch 1.3 学习笔记目录

    目录 Apache Nutch 1.3 学习笔记一 Apache Nutch 1.3 学习笔记二 Apache Nutch 1.3 学习笔记三(Inject) Apache Nutch 1.3 学习笔 ...

  3. Apache Nutch 1.3 学习笔记十一(页面评分机制 LinkRank 介绍)

    下面是Google翻译的http://wiki.apache.org/nutch/NewScoring内容,是关于Nutch 新的链接分数算法的说明,有点类似于Google的PageRank,这里有其 ...

  4. Polyworks脚本开发学习笔记(十八)-用SDK开发Polyworks插件

    Polyworks脚本开发学习笔记(十八)-用SDK开发Polyworks插件 插件是由PolyWorks加载的动态链接库(DLL文件),然后查询Polyworks模块,以确定它们具有哪些功能,提供给 ...

  5. IOS之学习笔记十五(协议和委托的使用)

    1.协议和委托的使用 1).协议可以看下我的这篇博客 IOS之学习笔记十四(协议的定义和实现) https://blog.csdn.net/u011068702/article/details/809 ...

  6. 吴恩达《机器学习》学习笔记十四——应用机器学习的建议实现一个机器学习模型的改进

    吴恩达<机器学习>学习笔记十四--应用机器学习的建议实现一个机器学习模型的改进 一.任务介绍 二.代码实现 1.准备数据 2.代价函数 3.梯度计算 4.带有正则化的代价函数和梯度计算 5 ...

  7. 吴恩达《机器学习》学习笔记十二——机器学习系统

    吴恩达<机器学习>学习笔记十二--机器学习系统 一.设计机器学习系统的思想 1.快速实现+绘制学习曲线--寻找重点优化的方向 2.误差分析 3.数值估计 二.偏斜类问题(类别不均衡) 三. ...

  8. 吴恩达《机器学习》学习笔记十——神经网络相关(2)

    吴恩达<机器学习>学习笔记十--神经网络相关(2) 一. 代价函数 二. 反向传播算法 三. 理解反向传播算法 四. 梯度检测 五. 随机初始化 1.全部初始化为0的问题 2.随机初始化的 ...

  9. Mr.J-- jQuery学习笔记(十九)--自定义动画实现图标特效

    之前有写过自定义动画Mr.J-- jQuery学习笔记(十八)--自定义动画 这次实现一个小demo 图标特效 页面渲染 <!DOCTYPE html> <html lang=&qu ...

最新文章

  1. Spring Boot 中的 @EnableAutoConfiguration 是如何处理的?
  2. ZYAR20A 亚克力2驱 蓝牙 298寻迹避障机器人 —— 小车前后左右综合实验
  3. 15、四大组件--BroadcastReceiver
  4. 【UI/UX】深度解析模态窗口
  5. PAT B1034 有理数四则运算 (20 分)
  6. php 压缩html css,PHP实现动态压缩js与css文件的方法
  7. 操作系统如何恢复到原先状态
  8. 拉普拉斯变换转换简表
  9. 服务器应用层次划分,服务器按应用层次划分的话可以分为哪几种?
  10. 阅读ArrayList源码的一些记录
  11. 奶奶说标题不能起的太长要不然会有憨憨跟着读之Linux简述及常用命令
  12. “80后”全国模范检察官白静:传递青年干警正能量
  13. 【NAT网络地址转换(私网公网地址、静态NAT、动态NAT、NAPT、Easy IP、NAT Server)】-20211215、20211216
  14. wps html编辑表格,手机wps中怎样编辑表格?手机wps编辑表格的方法
  15. unity3D 涂涂乐使用shader实现上色效果
  16. oh-my-zsh配置 alias 指定指令别名
  17. amd、cmd、esmodule、commonjs区别
  18. [笔记]深入解析Windows操作系统《三》系统机制
  19. 谈用url重写的方法替代生成静态页面的好处
  20. 随机画五角星,空心五角星

热门文章

  1. Atlassian 域名被曝一次点击账户接管漏洞 可导致供应链攻击
  2. 这些严重的 Slack桌面劫持漏洞仅值区区1750美元?
  3. IIS 设置默认首页静态页,无静态页,走路由
  4. Mac 安装php redis扩展
  5. 红包不是你想送就能送 摩拜物联网技术成行业壁垒
  6. PLSQL实现显示当天是星期几
  7. innodb 共享表空间 转 独立表空间 详细说明
  8. Netflix的Hystrix使用教程
  9. Spring Autowiring @Qualifier example
  10. Android入门学习4