当某个插件需要被加载时, Nutch 会加载所有插件的相关接口到缓存,此后每个插件需要实例的时候,根据相关接口和相关接口实现实例在缓存内的记录,使用反射实现一个实例并返回,下面以 QueryFilter 的所有插件被加载例子进行说明。
具体代码参看org.apache.nutch.seacher.QueryFilters<init>
( 1 )当第一次需要得到 QueryFilter 的一个子类的实例时,使用下面这句话试图获得所有的实例:
this.queryFilters =
(QueryFilter[]) conf.getObject(QueryFilter.class .getName());
(2 )如果为空,则试图从插件仓库中得到该插件的扩展点:
ExtensionPoint point = PluginRepository.get(conf)
.getExtensionPoint(QueryFilter.X_POINT_ID);
在 PluginRepository.get(conf) 这句话中,返回插件仓库,如果仓库为空,会初始化所有插件:
初始化所有插件PluginRepository.<init> |
① 试图从缓存内获得插件仓库。 PluginRepository result = (PluginRepository)CACHE.get(conf); ② 如果未获得,则初始化所有插件 result = new PluginRepository(conf); l 初始化以活动插件和扩展点的集合 fActivatedPlugins = new HashMap(); fExtensionPoints = new HashMap(); this.conf = conf; l 获得插件存放位置 String[] pluginFolders = conf.getStrings("plugin.folders"); l 实例化PluginManifestParser : PluginManifestParser manifestParser = new PluginManifestParser(conf, this); PluginManifestParser 是一个封装了PluginRepository 的工具类,在构造时,分析每个插件的文件夹,把每个plugin.xml 文件的内容进行分析,记录了所有的插件接口和插件接口内所包含的所有实现类的关系。 l 放入缓存 CACHE.put(conf, result);
Plugin.xml 描述内容见附录一 |
(3 )获得所有QueryFilter 的子类描述。
Extension[] extensions = point.getExtensions();
(4 )循环获得每个插件的两个参数,fieldName 和rawFieldNames ,生成每个filter 插件实例。
for (int i = 0; i < extensions.length; i++) {
Extension extension = extensions[i];
ArrayList fieldNames = parseFieldNames(extension, "fields");
ArrayList rawFieldNames = parseFieldNames(extension, "raw-fields");
if (fieldNames.size() == 0 && rawFieldNames.size() == 0) {
if (LOG.isWarnEnabled()) {
LOG.warn("QueryFilter: " + extension.getId()
+ " names no fields.");
}
continue;
}
filters[i] = (QueryFilter) extension.getExtensionInstance();
FIELD_NAMES.addAll(fieldNames);
FIELD_NAMES.addAll(rawFieldNames);
conf.setObject("FIELD_NAMES", FIELD_NAMES);
RAW_FIELD_NAMES.addAll(rawFieldNames);
conf.setObject("RAW_FIELD_NAMES", RAW_FIELD_NAMES);
}
至此,所有实现QueryFilter的子类实例均被加载。如果需要开发自己的插件,同样可以参考这个过程,plugin.xml的具体内容的描述负在下面:
<?xml version="1.0" encoding="UTF-8"?>
<!— 插件的根元素,根元素的属性表明了一个插件的基本身份-->
<plugin id=” 唯一身份(被插件仓库作为身份标示)” name=” 名称” version=” 版本号”
provider=” 作者”class=” 类名(可选)”>
<!-- 以下两个内容中引用的类库,都是作为本类使用反射时生成实例所需要的类库-->
<runtime>
<library name=" 运行时的类库">
<!— 如果存在此元素,则保存到fExportedLibs (输出类库集合),否则存放到
fNotExportedLibs (非输出类库集合)-->
<export name="*"/>
</library>
</runtime>
<requires>
<!— 需要注意,此处所需要的类库,包括该类库所需的类库,都不得在此引用本插件-->
<import plugin=" 所需类库"/>
</requires>
<extension id=" 本类的包名(从代码中看没有被使用)"
name=" 类名(从代码中看没有被使用)"
point=" 扩展点类名(即接口名)">
<implementation id=" 实现扩展的唯一标识(与类名相同,被parse-plugins.xml
作为身份表示使用)"
class=" 实现扩展的类的类名"/>
<parameter name=" 参数名" value=" 参数值"/>
</extension>
<!— 仅在nutch-extensionpoints/plugin.xml 中存在,一次性加载纪录下所有的扩展点的名称-->
< extension-point id=” 扩展点唯一标识”name=” 扩展点名”/>
</plugin>
下次会写一个完整的plugin以供参考。
摘自http://www.blogjava.net/redmu/archive/2006/12/02/85092.html