Nutch 插件系统浅析.docx
《Nutch 插件系统浅析.docx》由会员分享,可在线阅读,更多相关《Nutch 插件系统浅析.docx(12页珍藏版)》请在冰豆网上搜索。
Nutch插件系统浅析
本文中,您可以通过研究分析Nutch插件系统的内部架构和流程,来掌握Nutch插件系统的核心设计。
架构师可参考Nutch的插件系统设计出更加灵活的系统架构。
Nutch基本情况
Nutch是Apache基金会的一个开源项目,它原本是开源文件索引框架Lucene项目的一个子项目,后来渐渐发展成长为一个独立的开源项目。
它基于Java开发,基于Lucene框架,提供Web网页爬虫功能。
另外很吸引人的一点在于,它提供了一种插件框架,使得其对各种网页内容的解析、各种数据的采集、查询、集群、过滤等功能能够方便的进行扩展,正是由于有此框架,使得Nutch的插件开发非常容易,第三方的插件也层出不穷,极大的增强了Nutch的功能和声誉。
本文就是主要描述这个插件框架内部运行的机制和原理。
回页首
Nutch的插件体系结构
在Nutch的插件体系架构下,有些术语需要在这里解释:
1.扩展点ExtensionPoint
扩展点是系统中可以被再次扩展的类或者接口,通过扩展点的定义,可以使得系统的执行过程变得可插入,可任意变化。
2.扩展Extension
扩展式插件内部的一个属性,一个扩展是针对某个扩展点的一个实现,每个扩展都可以有自己的额外属性,用于在同一个扩展点实现之间进行区分。
扩展必须在插件内部进行定义。
3.插件Plugin
插件实际就是一个虚拟的容器,包含了多个扩展Extension、依赖插件RequirePlugins和自身发布的库Runtime,插件可以被启动或者停止。
Nutch为了扩展,预留了很多扩展点ExtenstionPoint,同时提供了这些扩展点的基本实现Extension,Plugin用来组织这些扩展,这些都通过配置文件进行控制,主要的配置文件包括了多个定义扩展点和插件(扩展)的配置文件,一个控制加载哪些插件的配置文件。
体系结构图如下:
图1.Nutch插件体系结构图
回页首
插件的内部结构
图2.插件的内部结构
1.runtime属性描述了其需要的Jar包,和发布的Jar包
2.requires属性描述了依赖的插件
3.extension-point描述了本插件宣布可扩展的扩展点
4.extension属性则描述了扩展点的实现
典型的插件定义:
id="query-url"插件的ID
name="URLQueryFilter"插件的名字
version="1.0.0"插件的版本
provider-name="nutch.org">插件的提供者ID
依赖的Jar包
发布的Jar包
依赖的插件
name="NutchURLQueryFilter"扩展的名字
point="org.apache.nutch.searcher.QueryFilter">扩展的扩展点ID
class="org.apache.nutch.searcher.url.URLQueryFilter">实现类
实现的相关属性
回页首
插件主要配置
1.plugin.folders:
插件所在的目录,缺省位置在plugins目录下。
plugin.folders
plugins
Directorieswherenutchpluginsarelocated.Each
elementmaybearelativeorabsolutepath.Ifabsolute,itisused
asis.Ifrelative,itissearchedforontheclasspath.
2.plugin.auto-activation:
当被配置为过滤(即不加载),但是又被其他插件依赖的时候,是否自动启动,缺省为true。
plugin.auto-activation
true
Definesifsomepluginsthatarenotactivatedregarding
theplugin.includesandplugin.excludespropertiesmustbeautomaticaly
activatediftheyareneededbysomeactivedplugins.
3.plugin.includes:
要包含的插件名称列表,支持正则表达式方式定义。
plugin.includes
protocol-http|urlfilter-regex|parse-(text|html|js)|index-(basic|anchor)
|query-(basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|
urlnormalizer-(pass|regex|basic)
Regularexpressionnamingplugindirectorynamesto
include.Anypluginnotmatchingthisexpressionisexcluded.
Inanycaseyouneedatleastincludethenutch-extensionpointsplugin.By
defaultNutchincludescrawlingjustHTMLandplaintextviaHTTP,
andbasicindexingandsearchplugins.InordertouseHTTPSpleaseenable
protocol-httpclient,butbeawareofpossibleintermittentproblemswiththe
underlyingcommons-httpclientlibrary.
4.plugin.excludes:
要排除的插件名称列表,支持正则表达式方式定义。
plugin.excludes
Regularexpressionnamingplugindirectorynamestoexclude.
回页首
插件主要类UML图
图3.插件主要类UML图(查看大图)
类包括:
1.PluginRepository是一个通过加载Iconfiguration配置信息初始化的插件库,里面维护了系统中所有的扩展点ExtensionPoint和所有的插件Plugin实例
2.ExtensionPoint是一个扩展点,通过扩展点的定义,插件Plugin才能定义实际的扩展Extension,从而实现扩展,每个ExtensionPoint类实例都维护了宣布实现了此扩展点的扩展Extension.
3.Plugin是一个虚拟的组织,提供了一个启动start和一个shutdown方法,从而实现了插件的启动和停止,他还有一个描述对象PluginDescriptor,负责保存此插件相关的配置信息,另外还有一个PluginClassLoader负责此插件相关类和库的加载。
回页首
插件加载过程
图4.插件加载过程时序图(查看大图)
通过序列图可以发现,Nutch加载插件的过程需要actor全程直接调用每个关联对象,最终得到的是插件的实现对象。
详细过程如下:
1.首先通过PluginRepository.getConf()方法加载配置信息,配置的内容包括插件的目录,插件的配置文件信息plugin.properties等,此时pluginrepository将根据配置信息加载各个插件的plugin.xml,同时根据Plugin.xml加载插件的依赖类。
2.当actor需要加载某个扩展点的插件的时候,他可以:
a.首先根据扩展点的名称,通过PluginRepository得到扩展点的实例,即ExtensionPoint类的实例;
b.然后调用ExtensionPoint对象的getExtensions方法,返回的是实现此扩展点的实例列表(Extension[]);
c.对每个实现的扩展实例Extension,调用它的getExtensionInstance()方法,以得到实际的实现类实例,此处为Object;
d.根据实际情况,将Object转型为实际的类对象类型,然后调用它们的实现方法,例如helloworld方法。
回页首
插件的典型调用方式
得到某个语言例如“GBK”扩展点的实例:
this.extensionPoint.getExtensions();//得到扩展点的所有扩展
for(inti=0;iif(“GBK”.equals(extensions[i].getAttribute("lang"))){//找到某个属性的扩展
returnextensions[i];//返回
}
}
}
extension.getExtensionInstance()//得到此扩展实现的实例对象
回页首
插件类加载机制
实际整个系统如果使用了插件架构,则插件类的加载是由PluginClassLoader类完成的,每个Plugin都有自己的classLoader,此classloader继承自URLClassLoader,并没有做任何事情:
publicclassPluginClassLoaderextendsURLClassLoader{
/**
*Construtor
*
*@paramurls
*Arrayofurlswithownlibrariesandallexportedlibrariesof
*pluginsthatarerequiredtothisplugin
*@paramparent
*/
publicPluginClassLoader(URL[]urls,ClassLoaderparent){
super(urls,parent);
}
}
这个classloader是属于这个插件的,它只负责加载本插件相关的类、本地库和依赖插件的发布(exported)库,也包括一些基本的配置文件例如.properties文件。
此类的实例化过程:
if(fClassLoader!
=null)
returnfClassLoader;
ArrayListarrayList=newArrayList();
arrayList.addAll(fExportedLibs);
arrayList.addAll(fNotExportedLibs);
arrayList.addAll(getDependencyLibs());
Filefile=newFile(getPluginPath());
try{
for(Filefile2:
file.listFiles()){
if(file2.getAbsolutePath().endsWith("properties"))
arrayList.add(file2.getParentFile().toURL());
}
}catch(MalformedURLExceptione){
LOG.debug(getPluginId()+""+e.toString());
}
URL[]urls=arrayList.toArray(newURL[arrayList.size()]);
fClassLoader=newPluginClassLoader(urls,PluginDescriptor.class
.getClassLoader());
returnfClassLoader;
∙首先判断缓存是否存在
∙加载需要的Jar包、自身需要的Jar包,依赖插件发布的Jar包
∙加载本地的properties文件
∙构造此classloader,父classloader为PluginDescriptor的加载者,通常是contextClassLoader
回页首
总结
Nutch是一个非常出色的开源搜索框架,它的插件架构更加是它的一个技术亮点,通过此架构,可以保证Nutch方便的被灵活的扩展而不用修改原来的代码,通过配置文件可以简单方便的控制加载或者不加载哪些插件,而且这些都不需要额外的容器支持。
这些都是我们在系统架构设计的时候可以学习和参考的有益经验。
参考资料
学习
∙查看网站“Nutch官方网站”,了解Nutch的基本情况。
∙“Nutch实战”(developerWorks,2008年11月):
本文介绍了开源搜索引擎Nutch的基本信息,并详细说明了在Eclispe下运行Nutch的步骤和需要注意的问题。
∙“开发基于Nutch的集群式搜索引擎”(developerWorks,2008年10月):
本文首先介绍Nutch的背景知识,包括Nutch架构,爬虫和搜索器。
然后以开发一个基于Nutch的实际应用为例向读者展示如何使用Nutch开发自己的搜索引擎。
∙developerWorksJava技术专区:
查找关于Java编程各方面的数百篇文章。