处理链和Processor

处理器链包括以下几种:
1 PreProcessor
2 Fetcher
3Extractor
4 Writer
5PostProcessor

为了很好的表示整个处理器链的逻辑结构,以及它们之间的链式调用关系,Heritrix设计了几个API来表示这种逻辑结构。

org.archive.crawler.framework.Processor
org.archive.crawler.framework.ProcessorChain
org.archive.crawler.framework.ProcessorChainList

下面进行详细讲解。
1.Processor类
该类代表着单个的处理器,所有的处理器都是它的子类。在Processor类中有一个process()
方法,它被标识为final类型的,也就是说,它不可以被它的子类所覆盖。代码如下。

public final void process(CrawlURI curi) throws InterruptedException
{
// 设置下一个处理器
curi.setNextProcessor(getDefaultNextProcessor(curi));

try
{
// 判断当前这个处理器是否为enabled
if ( ! ((Boolean) getAttribute(ATTR_ENABLED, curi)).booleanValue()) {
return ;
}
}
catch (AttributeNotFoundException e) {
logger.severe(e.getMessage());
}

// 如果当前的链接能够通过过滤器
// 则调用innerProcess(curi)方法
// 来进行处理
if (filtersAccept(curi)) {
innerProcess(curi);
}
// 如果不能通过过滤器检查,则调
// 用innerRejectProcess(curi)来处理
else
{
innerRejectProcess(curi);
}
}

((Boolean) getAttribute(ATTR_ENABLED, curi)).booleanValue()说明上例是将先得到一个curi对象,然后再调用这个对象的booleanValue()方法返回其对应的boolean数值。

更多详解请登录http://crawler.archive.org/apidocs/org/archive/crawler/framework/Processor.html。

方法的含义很简单。即首先检查是否允许这个处理器处理该链接,如果允许,则检查当前处理器所自带的过滤器是否能够接受这个链接。当过滤器的检查也通过后,则调用innerProcess(curi)方法来处理,如果过滤器的检查没有通过,就使用innerRejectProcess(curi)方法处理。
其中innerProcess(curi)和innerRejectProcess(curi)方法都是protected类型的,且本身没有实现任何内容。很明显它们是留在子类中,实现具体的处理逻辑。不过大部分的子类都不会重写innerRejectProcess(curi)方法了,这是因为反正一个链接已经被当前处理器拒绝处理了,就不用再有什么逻辑了,直接跳到下一个处理器继续处理就行了。

2.ProcessorChain类

该类表示一个队列,里面包括了同种类型的几个Processor。例如,可以将一组的Extractor加入到同一个ProcessorChain中去。
在一个ProcessorChain中,有3个private类型的类变量:

private final MapType processorMap;
private ProcessorChain nextChain;
private Processor firstProcessor;

其中,processorMap中存放的是当前这个ProcessorChain中所有的Processor。nextChain的类型是ProcessorChain,它表示指向下一个处理器链的指针。而firstProcessor则是指向当前队列中的第一个处理器的指针。

3.ProcessorChainList
从名称上看,它保存了Heritrix一次抓取任务中所设定的所有处理器链,将之做为一个列表。正常情况下,一个ProcessorChainList中,应该包括有5个ProcessorChain,分别为PreProcessor链、Fetcher链、Extractor链、Writer链和PostProcessor链,而每个链中又包含有多个的Processor。这样,就将整个处理器结构合理的表示了出来。
那么,在ToeThread的processCrawlUri()方法中,又是如何来将一个链接循环经过这样一组
结构的呢?请看下面的代码:

private void processCrawlUri() throws InterruptedException {
// 设定当前线程的编号
currentCuri.setThreadNumber( this .serialNumber);
// 为当前处理的URI设定下一个ProcessorChain

currentCuri.setNextProcessorChain(controller.getFirstProcessorChain());

// 设定开始时间
lastStartTime = System.currentTimeMillis();
try {

// 如果还有一个处理链没处理完
while (currentCuri.nextProcessorChain() != null )
{
setStep(STEP_ABOUT_TO_BEGIN_CHAIN);

// 将下个处理链中的第一个处理器设定为
// 下一个处理当前链接的处理器
currentCuri.setNextProcessor(currentCuri
.nextProcessorChain().getFirstProcessor()
);
// 将再下一个处理器链设定为当前链接的
// 下一个处理器链,因为此时已经相当于
// 把下一个处理器链置为当前处理器链了
currentCuri.setNextProcessorChain(currentCuri
.nextProcessorChain().getNextProcessorCha
in());

// 开始循环处理当前处理器链中的每一个Processor
while (currentCuri.nextProcessor() != null )
{
setStep(STEP_ABOUT_TO_BEGIN_PROCESSOR);
Processor currentProcessor
=
getProcessor(currentCuri.nextProcessor());
currentProcessorName
= currentProcessor.getName();
continueCheck();
// 调用Process方法
currentProcessor.process(currentCuri);
}
}
setStep(STEP_DONE_WITH_PROCESSORS);
currentProcessorName
= "" ;
}
catch (RuntimeExceptionWrapper e) {
// 如果是Berkeley DB的异常
if (e.getCause() == null ) {
e.initCause(e.getDetail());
}
recoverableProblem(e);
}
catch (AssertionError ae) {
recoverableProblem(ae);
}
catch (RuntimeException e) {
recoverableProblem(e);
}
catch (StackOverflowError err) {
recoverableProblem(err);
}
catch (Error err) {
seriousError(err);
}
}

SerialNumber 属性

返回十进制序列号,用于唯一标识一个磁盘卷。object.SerialNumber object 应为 Drive 对象的名称。

代码使用了双重循环来遍历整个处理器链的结构,第一重循环首先遍历所有的处理器链,第二重循环则在链内部遍历每个Processor,然后调用它的process()方法来执行处理逻辑。

你可能感兴趣的:(处理链和Processor)