Nutch的插件机制,具有很好的扩展性,这里讨论一下其实现机制。
从URLFilters入手吧。
类URLFilters中,有个静态方法:
static {
。。。。
try {
ExtensionPoint point =
PluginRepository.getInstance().getExtensionPoint(URLFilter.X_POINT_ID);
。。。
}
跟踪到PluginRepository.getInstance(). 在PluginRepository.PluginRepository() 构造函数中,
(1) fRegisteredPlugins = getDependencyCheckedPlugins(PluginManifestParser
.parsePluginFolder());
(2) installExtensions(fRegisteredPlugins);
待会再说installExtensions(fRegisteredPlugins); 先看 fRegisteredPlugins =getDependencyCheckedPlugins(PluginManifestParser
.parsePluginFolder());
PluginManifestParser.parsePluginFolder()是什么意思呢?继续往下看。
把PluginManifestParser这个类通读一遍,知道葫芦里卖什么药了。
原来是,首先读取nutch-default.xml文件中的plugin.folders,知道插件文件夹的存放位置。然后遍历这个文件夹下面的每个插件(一个插件对应一个文件夹,每个文件件下还有一个plugin.xml。于是N个插件对应N个plugin.xml。每个plugin.xml用一个PluginDescriptor的类来保留其信息。
必须要注意的是:nutch-default.xml中plugin.includes和plugin.excludes在这个过程当中使用到了,对于每个插件、根据其文件夹名来确定是否过滤该插件。
PluginManifestParser.parsePluginFolder()返回一个list,list中的每个item就是一个PluginDescriptor类的实例。
这里要提到的一点是:PluginDescriptor是一个通用的插件描述类。以Nutch0.7为例,就有两种不同的plugin.xml。比如nutch-extensionpoints下的plugin.xml和urlfilter-regex下的plugin.xml就不同。
第一种就是带有
<extension id="org.apache.nutch.net.urlfiler"
name="Nutch Regex URL Filter"
point="org.apache.nutch.net.URLFilter">
<implementation id="RegexURLFilter"
class="org.apache.nutch.net.RegexURLFilter"/>
<!-- by default, attribute "file" is undefined, to keep classic behavior.
<implementation id="RegexURLFilter"
class="org.apache.nutch.net.RegexURLFilter"
file="urlfilter-regex.txt"/>
-->
</extension>
第二种带有:
<extension-point
id="org.apache.nutch.clustering.OnlineClusterer"
name="Nutch Online Search Results Clustering Plugin"/>
<extension-point
id="org.apache.nutch.indexer.IndexingFilter"
name="Nutch Indexing Filter"/>
<extension-point
id="org.apache.nutch.ontology.Ontology"
name="Ontology Model Loader"/>
PluginManifestParser.parsePluginFolder()返回的list中,这两种都有可能。
现在回头来看
(1) fRegisteredPlugins = getDependencyCheckedPlugins(PluginManifestParser
.parsePluginFolder());
关于 descriptor.getDependencies() 方面的code,暂时没有执行到,不用管它。每个插件取出后,加入返回的list当中,如果plugin.xml是第二种情况的话,把它加入fExtensionPoints map中。
fExtensionPoints.put(xpId, point);
xpId 比如:org.apache.nutch.clustering.OnlineClusterer;
point 是描述这样的一个XML element:
<extension-point id="org.apache.nutch.indexer.IndexingFilter" name="Nutch Indexing Filter"/>
(2) installExtensions(fRegisteredPlugins); 这个是关键的!
依次取出PluginDescriptor descriptor,如果有extension,那些PluginDescriptor 才有extension描述符,第一种plugin.xml。对于这种描述符,比如:
<extension id="org.apache.nutch.net.urlfiler"
name="Nutch Regex URL Filter"
point="org.apache.nutch.net.URLFilter">
<implementation id="RegexURLFilter"
class="org.apache.nutch.net.RegexURLFilter"/>
<!-- by default, attribute "file" is undefined, to keep classic behavior.
<implementation id="RegexURLFilter"
class="org.apache.nutch.net.RegexURLFilter"
file="urlfilter-regex.txt"/>
-->
</extension>
根据其point值,到fExtensionPoints中取其对应的ExtensionPoint,然后extension加入到ExtensionPoint。
这样实现了这样的Mapping:
point值(实际上就是类的完整名字),找到对应的类实现(可以多个),然后就可以new instance了。