Heritrix 3.1.0 소스 해석(14)
39079 단어 Heritrix
본고는 다음에 다중 루틴 환경에서Heritrix3을 분석한다.1.0 시스템에서 관련 객체 속성의 일관성을 유지하는 방법 및 관련 객체의 속성 값을 사용자 정의하여 구성하는 방법
Work Queue Frontier 클래스의void schedule(Crawl URI curi) 방법에서 볼 수 있습니다.
@Override
public void schedule(CrawlURI curi) {
sheetOverlaysManager.applyOverlaysTo(curi);
try {
KeyedProperties.loadOverridesFrom(curi);
//KeyedProperties.withOverridesDo(ocontext, todo)
if(curi.getClassKey()==null) {
// remedial processing
preparer.prepare(curi);
}
processScheduleIfUnique(curi);
} finally {
KeyedProperties.clearOverridesFrom(curi);
}
}
Sheet Overlays Manager 대상과 Keyed Properties 대상과 관련이 있습니다. 우선 Keyed Properties 클래스는Concurrent HashMap
이것은 맵 키 값이 맞는 형식으로 상하문에 대상을 저장하는 속성입니다. 이것은 우리가 필요로 하는 속성을 ThreadLocal 변수에 저장합니다. (루트 국부 변수)
/**
* ThreadLocal (contextual) collection of pushed override maps
*/
static ThreadLocal<ArrayList<OverlayContext>> threadOverrides =
new ThreadLocal<ArrayList<OverlayContext>>() {
protected ArrayList<OverlayContext> initialValue() {
return new ArrayList<OverlayContext>();
}
};
ThreadLocal 대상에 저장된 대상은 ArrayList
/**
* Add an override map to the stack
* @param m Map to add
*/
static public void pushOverrideContext(OverlayContext ocontext) {
threadOverrides.get().add(ocontext);
}
/**
* Remove last-added override map from the stack
* @return Map removed
*/
static public OverlayContext popOverridesContext() {
// TODO maybe check that pop is as expected
return threadOverrides.get().remove(threadOverrides.get().size()-1);
}
static public void clearAllOverrideContexts() {
threadOverrides.get().clear();
}
static public void loadOverridesFrom(OverlayContext ocontext) {
assert ocontext.haveOverlayNamesBeenSet();
pushOverrideContext(ocontext);
}
static public boolean clearOverridesFrom(OverlayContext ocontext) {
return threadOverrides.get().remove(ocontext);
}
static public void withOverridesDo(OverlayContext ocontext, Runnable todo) {
try {
loadOverridesFrom(ocontext);
todo.run();
} finally {
clearOverridesFrom(ocontext);
}
}
public static boolean overridesActiveFrom(OverlayContext ocontext) {
return threadOverrides.get().contains(ocontext);
}
다음 방법은 키 값에 따라 속성 값을 가져오는 것입니다. (OverlayContext 인터페이스 리셋)
/** the alternate global property-paths leading to this map
* TODO: consider if deterministic ordered list is important */
HashSet<String> externalPaths = new HashSet<String>();
/**
* Add a path by which the outside world can reach this map
* @param path String path
*/
public void addExternalPath(String path) {
externalPaths.add(path);
}
/**
* Get the given value, checking override maps if appropriate.
*
* @param key
* @return discovered override, or local value
*/
public Object get(String key) {
ArrayList<OverlayContext> overlays = threadOverrides.get();
for(int i = overlays.size()-1; i>=0; i--) {
OverlayContext ocontext = overlays.get(i);
for(int j = ocontext.getOverlayNames().size()-1; j>=0; j--) {
String name = ocontext.getOverlayNames().get(j);
Map<String,Object> m = ocontext.getOverlayMap(name);
for(String ok : getOverrideKeys(key)) {
Object val = m.get(ok);
if(val!=null) {
return val;
}
}
}
}
return super.get(key);
}
/**
* Compose the complete keys (externalPath + local key name) to use
* for checking for contextual overrides.
*
* @param key local key to compose
* @return List of full keys to check
*/
protected List<String> getOverrideKeys(String key) {
ArrayList<String> keys = new ArrayList<String>(externalPaths.size());
for(String path : externalPaths) {
keys.add(path+"."+key);
}
return keys;
}
OverlayContext 인터페이스 소스는 다음과 같습니다.
/**
* Interface for objects that can contribute 'overlays' to replace the
* usual values in configured objects.
* @contributor gojomo
*/
public interface OverlayContext {
/** test if this context has actually been configured with overlays
* (even if in fact no overlays were added) */
public boolean haveOverlayNamesBeenSet();
/** return a list of the names of overlay maps to consider */
ArrayList<String> getOverlayNames();
/** get the map corresponding to the overlay name */
Map<String,Object> getOverlayMap(String name);
}
OverlayContext 인터페이스는 하나의 구현 클래스 CrawlURI만 있고 인터페이스 구현과 관련된 방법은 다음과 같다(OverlayMapsSource 인터페이스 리셋 방법)
//
// OverridesSource implementation
//
transient protected ArrayList<String> overlayNames = null;
transient protected OverlayMapsSource overlayMapsSource;
public boolean haveOverlayNamesBeenSet() {
return overlayNames != null;
}
public ArrayList<String> getOverlayNames() {
if(overlayNames == null) {
overlayNames = new ArrayList<String>();
}
return overlayNames;
}
public Map<String, Object> getOverlayMap(String name) {
return overlayMapsSource.getOverlayMap(name);
}
public void setOverlayMapsSource(OverlayMapsSource overrideMapsSource) {
this.overlayMapsSource = overrideMapsSource;
}
OverlayMapsSource 인터페이스 소스는 다음과 같습니다.
/**
* Interface for a source of overlay maps by name.
*
* @contributor gojomo
*/
public interface OverlayMapsSource {
public Map<String,Object> getOverlayMap(String name);
}
Overlay MapsSource 인터페이스는 클래스SheetOverlays Manager를 실현하고, SheetOverlays Manager 클래스는 BeanFactory Aware 인터페이스와ApplicationListener 인터페이스를 실현한다.
SheetOverlays Manager 클래스 구성원은 다음과 같습니다. (여기는 실질적으로 Sheet 설정과 CrawlURI 대상과 Sheet의 매핑)
BeanFactory beanFactory;
/** all SheetAssociations by DecideRule evaluation */
SortedSet<DecideRuledSheetAssociation> ruleAssociations =
new ConcurrentSkipListSet<DecideRuledSheetAssociation>();
NavigableMap<String,List<String>> sheetNamesBySurt = new ConcurrentSkipListMap<String,List<String>>();
/** all sheets by (bean)name*/
Map<String,Sheet> sheetsByName = new ConcurrentHashMap<String, Sheet>();
OverlayMapsSource 인터페이스 구현 방법(키(String name 매개 변수)에 따라 Sheet 대상을 가져오고 Sheet 대상의 Map 용기 대상을 가져옴)
/**
* Retrieve the named overlay Map.
*
* @see org.archive.spring.OverlayMapsSource#getOverlayMap(java.lang.String)
*/
public Map<String, Object> getOverlayMap(String name) {
return sheetsByName.get(name).getMap();
}
ApplicationListener 인터페이스 사항은 다음과 같습니다.
/**
* Ensure all sheets are 'primed' after the entire ApplicatiotnContext
* is assembled. This ensures target HasKeyedProperties beans know
* any long paths by which their properties are addressed, and
* handles (by either PropertyEditor-conversion or a fast-failure)
* any type-mismatches between overlay values and their target
* properties.
* @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
*/
public void onApplicationEvent(ApplicationEvent event) {
if(event instanceof ContextRefreshedEvent) {
for(Sheet s: sheetsByName.values()) {
s.prime(); // exception if Sheet can't target overridable properties
}
// log warning for any sheets named but not present
HashSet<String> allSheetNames = new HashSet<String>();
for(DecideRuledSheetAssociation assoc : ruleAssociations) {
allSheetNames.addAll(assoc.getTargetSheetNames());
}
for(List<String> names : sheetNamesBySurt.values()) {
allSheetNames.addAll(names);
}
for(String name : allSheetNames) {
if(!sheetsByName.containsKey(name)) {
logger.warning("sheet '"+name+"' referenced but absent");
}
}
}
}
sheet 설정에서 대상과 속성 형식이 일치하는지 확인하고, 그 다음에 설정에 존재하지 않는sheet 이름이 있는지 확인합니다. (초기화할 때 호출)
void applyOverlaysTo(CrawlURI curi) 방법
/**
* Apply the proper overlays (by Sheet beanName) to the given CrawlURI,
* according to configured associations.
*
* TODO: add guard against redundant application more than once?
* TODO: add mechanism for reapplying overlays after settings change?
* @param curi
*/
public void applyOverlaysTo(CrawlURI curi) {
curi.setOverlayMapsSource(this);
// apply SURT-based overlays
curi.getOverlayNames().clear(); // clear previous info
String effectiveSurt = SurtPrefixSet.getCandidateSurt(curi.getPolicyBasisUURI());
List<String> foundPrefixes = PrefixFinder.findKeys(sheetNamesBySurt, effectiveSurt);
for(String prefix : foundPrefixes) {
for(String name : sheetNamesBySurt.get(prefix)) {
curi.getOverlayNames().add(name);
}
}
// apply deciderule-based overlays
for(DecideRuledSheetAssociation assoc : ruleAssociations) {
if(assoc.getRules().accepts(curi)) {
curi.getOverlayNames().addAll(assoc.getTargetSheetNames());
}
}
// even if no overlays set, let creation of empty list signal
// step has occurred -- helps ensure overlays added once-only
curi.getOverlayNames();
}
먼저 CrawlURI curi 대상의 구성원 변수인 OverlayMapsSource overlayMapsSource를 설정하고 이 CrawlURI curi 대상의 설정을 불러옵니다. (키워드에 따라 다른 대상이 호출되고 관련 속성 값을 가져오는 데 사용)
우리가 지금 계속 알아야 할 것은 Sheet류이다. 먼저 Crawler-beans에 익숙해져라.cxml 파일의 설정 (클래스의 속성을 덮어쓰는 데 사용)
<!-- veryPolite: any URI to which this sheet's settings are applied
will cause its queue to take extra-long politeness snoozes -->
<bean id='veryPolite' class='org.archive.spring.Sheet'>
<property name='map'>
<map>
<entry key='disposition.delayFactor' value='10'/>
<entry key='disposition.minDelayMs' value='10000'/>
<entry key='disposition.maxDelayMs' value='1000000'/>
<entry key='disposition.respectCrawlDelayUpToSeconds' value='3600'/>
</map>
</property>
</bean>
Sheet의 구성원 변수는 다음과 같습니다.
/**
* unique name of this Sheet; if Sheet has a beanName from original
* configuration, that is always the name -- but the name might
* also be another string, in the case of Sheets added after
* initial container wiring
*/
String name;
/** map of full property-paths (from BeanFactory to individual
* property) and their changed value when this Sheet of overrides
* is in effect
*/
Map<String,Object> map = new ConcurrentHashMap<String, Object>();
void prime () 방법은 대상과 해당 속성 유형이 일치하는지 검사하는 데 사용됩니다
/**
* Ensure any properties targetted by this Sheet know to
* check the right property paths for overrides at lookup time,
* and that the override values are compatible types for their
* destination properties.
*
* Should be done as soon as all possible targets are
* constructed (ApplicationListener ContextRefreshedEvent)
*
* TODO: consider if an 'un-priming' also needs to occur to
* prevent confusing side-effects.
* TODO: consider if priming should move to another class
*/
public void prime() {
for (String fullpath : map.keySet()) {
int lastDot = fullpath.lastIndexOf(".");
String beanPath = fullpath.substring(0,lastDot);
String terminalProp = fullpath.substring(lastDot+1);
Object value = map.get(fullpath);
int i = beanPath.indexOf(".");
Object bean;
HasKeyedProperties hkp;
if (i < 0) {
bean = beanFactory.getBean(beanPath);
} else {
String beanName = beanPath.substring(0,i);
String propPath = beanPath.substring(i+1);
BeanWrapperImpl wrapper = new BeanWrapperImpl(beanFactory.getBean(beanName));
bean = wrapper.getPropertyValue(propPath);
}
try {
hkp = (HasKeyedProperties) bean;
} catch (ClassCastException cce) {
// targetted bean has no overridable properties
throw new TypeMismatchException(bean,HasKeyedProperties.class,cce);
}
// install knowledge of this path
hkp.getKeyedProperties().addExternalPath(beanPath);
// verify type-compatibility
BeanWrapperImpl wrapper = new BeanWrapperImpl(hkp);
Class<?> requiredType = wrapper.getPropertyType(terminalProp);
try {
// convert for destination type
map.put(fullpath, wrapper.convertForProperty(value,terminalProp));
} catch(TypeMismatchException tme) {
TypeMismatchException tme2 =
new TypeMismatchException(
new PropertyChangeEvent(
hkp,
fullpath,
wrapper.getPropertyValue(terminalProp),
value), requiredType, tme);
throw tme2;
}
}
}
위에서 주의해야 할 것은hkp이다.getKeyedProperties().addExternalPath(beanPath)
Keyed Properties 클래스의HashSet
추상 클래스 SheetAssociation 정의 대상 Sheet 객체의 이름 집합
/**
* Represents target Sheets that should be associated with
* some grouping of URIs.
*
* Subclasses specify the kind of association (as by SURT prefix
* matching, or arbitrary decide-rules).
*
* @contributor gojomo
*/
public abstract class SheetAssociation {
List<String> targetSheetNames = new LinkedList<String>();
public List<String> getTargetSheetNames() {
return targetSheetNames;
}
public void setTargetSheetNames(List<String> targetSheets) {
this.targetSheetNames = targetSheets;
}
}
SheetAssociation의 하위 클래스SurtPrefixes SheetAssociation, CrawlURI curi 대상의classkey 값과sheet 집합의 매핑을 설정합니다
/**
* SheetAssociation applied on the basis of matching SURT prefixes.
*
* @contributor gojomo
*/
public class SurtPrefixesSheetAssociation extends SheetAssociation {
List<String> surtPrefixes;
public List<String> getSurtPrefixes() {
return surtPrefixes;
}
@Required
public void setSurtPrefixes(List<String> surtPrefixes) {
this.surtPrefixes = surtPrefixes;
}
}
Crawler-beans에서.cxml 파일의 설정 예는 다음과 같다
<bean class='org.archive.crawler.spring.SurtPrefixesSheetAssociation'>
<property name='surtPrefixes'>
<list>
<value>http://(org,example,</value>
<value>http://(com,example,www,)/</value>
</list>
</property>
<property name='targetSheetNames'>
<list>
<value>veryPolite</value>
<value>smallBudget</value>
</list>
</property>
</bean>
SheetAssociation 클래스의 다른 하위 클래스인 DecideRuledSheetAssociation 코드는 다음과 같습니다. (DecideRule 대상과 Sheet 집합의 매핑을 설정하는 데 사용됩니다)
/**
* SheetAssociation applied on the basis of DecideRules. If the
* final ruling is ACCEPT, the named sheets will be overlaid.
*
* @contributor gojomo
*/
public class DecideRuledSheetAssociation extends SheetAssociation
implements Ordered, Comparable<DecideRuledSheetAssociation>, BeanNameAware {
DecideRule rules;
int order = 0;
public DecideRule getRules() {
return rules;
}
@Required
public void setRules(DecideRule rules) {
this.rules = rules;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
// compare on the basis of Ordered value
public int compareTo(DecideRuledSheetAssociation o) {
int cmp = order - ((Ordered)o).getOrder();
if(cmp!=0) {
return cmp;
}
return name.compareTo(o.name);
}
String name;
public void setBeanName(String name) {
this.name = name;
}
}
프로필crawler-beans.cxml에서 나는 아직 예시를 찾지 못했다. (그러나 우리는 사용자 정의 설정을 할 수 있다.)
---------------------------------------------------------------------------
본 시리즈의 Heritrix 3.1.0 원본 해석은 본인이 창작한 것입니다.
전재 는 출처 가 블로그 정원 고슴도치 의 온순함 을 밝혀 주십시오
본문 링크http://www.cnblogs.com/chenying99/archive/2013/04/20/3031937.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Heritrix 3.1.0 소스 해석(16)다음은 BdbFrontier 객체 CrawlURI next() 방법과 관련된 방법을 분석합니다. 이 방법은 좀 길어요. 먼저void wakeQueues() 방법을 볼게요. snoozedClassQueues.poll ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.