1. 실패한 건을 따로 Listener를 이용해서 특정 폴더에 쓴다던지 해서 모아두고, 그것을 처리하는 job을 따로 실행시키는 것이 나을듯합니다.ItemWriteListener.onWriteError 같은 것을 이용해서 실패한 건만 따로 이벤트 처리를 할 수 있습니다. 그 안에서 별도의 디렉토리에 쓴다던지DB에 표시한다던지해서(같이 롤백되지 않게 트랜잭션 처리 주의해야 합니다.) 한두시간 후에 별도의 스케뷸로 실패로 분류된 것만 다시 실행시킬 수 있습니다.
2. 여러가지 방법을 생각해볼수 있습니다. ItemProcessor를 이용해서 여러개의 ItemReader를 결합해서 부모,자식간의 처리를 해 줄수도 있습니다. DB의 부모-자식관계가 있는 엔티티를 XML로 옮기는 경우에 N+1쿼리 문제가 발생하지 않도록 2개의 JdbcCursorItemReader를 이용해서 키순대로 정렬해서 DB에서 조회해준다음에 ItemProcessor안에서 엮어서 XMl을 만드는 것도 해본적이 있습니다. (이 작업은 1.x대에서 해서 그때는 DelegateItemReader인가.. 그걸 썼었지요;)
그리고 보통은 ExcecutionContext를 이용해서 같은 step이나 job안에서 데이터를 공유하고, ItemListener와 ItemProcessor 등의 인터페이스를 동시에 구현하는 클래스를 만들어서 같은 클래스의 멤버변수로 데이터를 공유할 수도 있습니다. (이 경우에는 객체가 계속 쌓이지 않게 메모리 릭에 주의해야겠죠)
3. UrlResource를 바로 이용해서 연결해도 됩니다. 그런데 아무래도 나중에 실패시 추적등을 위해서 URL에서 파일로 download 받아 놓는 것이 좋은 것 같아서 저는 비슷한 경우에 다운로드를 하는 step를 하나 추가하고, 다운된 파일을 읽어서 xml파싱을 했었습니다. 아래와 같은 소스를 이용했었습니다.
public class ResourceCopyTasklet implements Tasklet {
private Resource source;
private Resource destination;
public void setSource(Resource source) {
this.source = source;
}
public void setDestination(Resource destination) {
this.destination = destination;
}
@Override
public RepeatStatus execute(StepContribution contribution,
ChunkContext chunkContext) throws Exception {
Assert.notNull(source,"source must not null");
Assert.notNull(destination,"destination must not null");
FileUtils.copyURLToFile(source.getURL(), destination.getFile());
contribution.incrementReadCount();
contribution.incrementWriteCount(1);
return RepeatStatus.FINISHED;
}
}
그리고 설정할때는 아래처럼하죠
<bean id="resouceCopyTasklet" class=".....ResourceCopyTasklet">
<property name="source" value="
http://www.naver.com"/>
<property name="destination" value="file:target/output.txt"/>
</bean>
아래와 같은 식으로 하면 다운로드한 파일에 jobParameter의 일부를 넣는 것도 가능합니다. (이때는 scope="step"으로 해야합니다.)
<property name="destination"
value="...download_#{jobParameters[downloadDate]}.xml" />
이렇게 각 시도때마다 일단 파일을 다운받아 놓으니 나중에 에러가 났을 때 추적하기도 괜찮더군요.