Java 从Spring批处理自定义ItemReader返回对象列表

Java 从Spring批处理自定义ItemReader返回对象列表,java,spring,spring-batch,vtd-xml,Java,Spring,Spring Batch,Vtd Xml,我需要处理数千笔付款。因此,我在Spring Batch中使用了VtdXml而不是StatxeventitemReader,我为相同的项目创建了自定义项目阅读器。为了使用多线程读取巨大的xml,我创建了10个线程的分区。我将巨大的xml文件拆分为10个文件,并分配给分区中的每个线程。一旦我阅读了xml,我将转换成对象列表并发送给Writer。在Writer中收到后,我将自定义对象列表并合并到最终列表中。每当我返回读取的对象列表时,我会再次调用它,并且它永远不会结束。如何将对象列表传递给编写器并合

我需要处理数千笔付款。因此,我在Spring Batch中使用了VtdXml而不是StatxeventitemReader,我为相同的项目创建了自定义项目阅读器。为了使用多线程读取巨大的xml,我创建了10个线程的分区。我将巨大的xml文件拆分为10个文件,并分配给分区中的每个线程。一旦我阅读了xml,我将转换成对象列表并发送给Writer。在Writer中收到后,我将自定义对象列表并合并到最终列表中。每当我返回读取的对象列表时,我会再次调用它,并且它永远不会结束。如何将对象列表传递给编写器并合并到最终列表中

public class VtdWholeItemReader<T> implements ResourceAwareItemReaderItemStream<T> {


private Resource resource;

private boolean noInput;

private boolean strict = true;

private InputStream inputStream;

private int index = 0;





@Override
public void open(ExecutionContext executionContext) {
    Assert.notNull(resource, "The Resource must not be null.");

    noInput = true;
    if (!resource.exists()) {
        if (strict) {
            throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode)");
        }
        log.warn("Input resource does not exist " + resource.getDescription());
        return;
    }
    if (!resource.isReadable()) {
        if (strict) {
            throw new IllegalStateException("Input resource must be readable (reader is in 'strict' mode)");
        }
        log.warn("Input resource is not readable " + resource.getDescription());
        return;
    }
    noInput = false;
}

@Override
public void update(ExecutionContext executionContext) {

}

@Override
public void close() {
    try {
        if (inputStream != null) {
            inputStream.close();
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } finally {
        inputStream = null;
    }

}

@Override
public void setResource(Resource resource) {
    this.resource = resource;
}

@Override
public T read()
        throws java.lang.Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
    if (noInput) {
        return null;
    }
    List<Payment> paymentList = new ArrayList<Payment>();

    try {
        VTDGen vg = new VTDGen();
        VTDGen vgHen = new VTDGen();
        boolean headercheck = true;
        if (vg.parseFile("src/main/resources/input/partitioner/" + resource.getFilename(), false)) {

            VTDNav vn = vg.getNav();
            AutoPilot ap = new AutoPilot(vn);
            ap.selectXPath("/root/Payment");
            // flb contains all the offset and length of the segments to be skipped
            FastLongBuffer flb = new FastLongBuffer(4);
            int i;
            byte[] xml = vn.getXML().getBytes();
            while ((i = ap.evalXPath()) != -1) {
                flb.append(vn.getElementFragment());
            }
            int size = flb.size();
            log.info("Payment Size {}", size);
            if (size != 0) {
                for (int k = 0; k < size; k++) {
                    String message = new String(xml, flb.lower32At(k), flb.upper32At(k), StandardCharsets.UTF_8);

                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

                    Payment payment = objectMapper
                            .readValue(message, Payment.class);
                    paymentList.add(pcPayment);
                    index = pcPaymentList.size() + 1;

                }
            }
            log.info("Payment List:: {}", paymentList.size());
            log.info("Index::{}", index);
            return index > paymentList .size() ? null : (T) paymentList;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

}  
公共类VtdWholeItemReader实现ResourceAwareItemReaderItemStream{
私人资源;
私有布尔无输入;
私有布尔严格=真;
私有输入流输入流;
私有整数指数=0;
@凌驾
公开作废打开(ExecutionContext ExecutionContext){
Assert.notNull(资源,“资源不能为null”);
noInput=true;
如果(!resource.exists()){
如果(严格){
抛出新的IllegalStateException(“输入资源必须存在(读卡器处于“严格”模式)”);
}
log.warn(“输入资源不存在”+resource.getDescription());
返回;
}
如果(!resource.isReadable()){
如果(严格){
抛出新的IllegalStateException(“输入资源必须可读(读卡器处于“严格”模式)”);
}
log.warn(“输入资源不可读”+resource.getDescription());
返回;
}
noInput=false;
}
@凌驾
公共无效更新(ExecutionContext ExecutionContext){
}
@凌驾
公众假期结束(){
试一试{
如果(inputStream!=null){
inputStream.close();
}
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}最后{
inputStream=null;
}
}
@凌驾
公共void集合资源(资源){
这个资源=资源;
}
@凌驾
公众阅读
抛出java.lang.Exception、UnexpectedInputException、ParseException、NontTransientResourceException{
如果(无输入){
返回null;
}
List paymentList=新建ArrayList();
试一试{
VTDGen vg=新VTDGen();
VTDGen vgHen=新VTDGen();
布尔headercheck=true;
if(vg.parseFile(“src/main/resources/input/partitioner/”+resource.getFilename(),false)){
VTDNav vn=vg.getNav();
自动驾驶仪ap=新自动驾驶仪(vn);
ap.选择XPath(“/root/Payment”);
//flb包含要跳过的段的所有偏移和长度
FastLongBuffer flb=新的FastLongBuffer(4);
int i;
字节[]xml=vn.getXML().getBytes();
而((i=ap.evalXPath())!=-1){
append(vn.getElementFragment());
}
int size=flb.size();
log.info(“付款大小{}”,大小);
如果(大小!=0){
对于(int k=0;kpaymentList.size()?空:(T)paymentList;
}
}捕获(例外e){
e、 printStackTrace();
}
返回null;
}
}  
SpringBatch配置类

private final Logger logger = LoggerFactory.getLogger(SpringBatchConfig.class);

@Autowired
private JobBuilderFactory jobBuilderFactory;

@Autowired
private StepBuilderFactory stepBuilderFactory;

@Autowired
ResourcePatternResolver resoursePatternResolver;


@Bean
public Job job() {
    return jobBuilderFactory.get("job").start(readpayment()).build();
}

@Bean
public JobLauncher jobLauncher() throws Exception {
    SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
    jobLauncher.setJobRepository(jobRepository());
    jobLauncher.afterPropertiesSet();
    return jobLauncher;
}

@Bean
public JobRepository jobRepository() throws Exception {
    MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
    factory.setTransactionManager(new ResourcelessTransactionManager());
    return (JobRepository) factory.getObject();
}

@Bean
protected Step readpayment() {
    return stepBuilderFactory.get("readpayment").partitioner("paymentStep", partitioner(null))
            .step(paymentStep()).taskExecutor(taskExecutor()).build();
}

@Bean
protected Step paymentStep() {
    return stepBuilderFactory.get("paymentStep")
            .<Payment,Payment>chunk(10)
         .reader(xmlFileItemReader(null))
        .writer(writer()).build();
}


@Bean
public TaskExecutor taskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setMaxPoolSize(10);
    taskExecutor.setCorePoolSize(10);
    taskExecutor.setQueueCapacity(10);
    taskExecutor.afterPropertiesSet();
    return taskExecutor;
}

@Bean
@StepScope
ItemReader<Payment> xmlFileItemReader(@Value("#{stepExecutionContext[fileName]}") String filename) {
    VtdWholeItemReader<Payment> xmlFileReader = new VtdWholeItemReader<>();
    xmlFileReader.setResource(new ClassPathResource("input/partitioner/" + filename));
    return xmlFileReader;
}

@Bean
@StepScope
public CustomMultiResourcePartitioner partitioner(@Value("#{jobParameters['fileName']}") String fileName) {
    logger.info("fileName {}", fileName);
    CustomMultiResourcePartitioner partitioner = new CustomMultiResourcePartitioner();
    Resource[] resources;
    try {
        resources = resoursePatternResolver.getResources("file:src/main/resources/input/partitioner/*.xml");
    } catch (IOException e) {
        throw new RuntimeException("I/O problems when resolving the input file pattern.", e);
    }
    partitioner.setResources(resources);
    return partitioner;
}

@Bean
public ItemWriter<Payment> writer() {
    return new PaymentItemWriter();
}
private final Logger Logger=LoggerFactory.getLogger(SpringBatchConfig.class);
@自动连线
私人JobBuilderFactory JobBuilderFactory;
@自动连线
私人StepBuilderFactory StepBuilderFactory;
@自动连线
资源模式分解器资源模式分解器;
@豆子
公职{
返回jobBuilderFactory.get(“作业”).start(readpayment()).build();
}
@豆子
PublicJobLauncher JobLauncher()引发异常{
SimpleJobLauncher jobLauncher=新的SimpleJobLauncher();
setJobRepository(jobRepository());
jobLauncher.AfterPropertieSet();
返回作业启动器;
}
@豆子
public JobRepository JobRepository()引发异常{
MapJobRepositoryFactoryBean工厂=新的MapJobRepositoryFactoryBean();
setTransactionManager(新的ResourcesTransactionManager());
return(JobRepository)factory.getObject();
}
@豆子
受保护的步骤readpayment(){
return stepBuilderFactory.get(“readpayment”).partitioner(“paymentStep”,partitioner(null))
.step(paymentStep()).taskExecutor(taskExecutor()).build();
}
@豆子
受保护的步骤付款步骤(){
return stepBuilderFactory.get(“paymentStep”)
.chunk(10)
.reader(xmlFileItemReader(null))
.writer(writer()).build();
}
@豆子
公共任务执行器任务执行器(){
ThreadPoolTaskExecutor taskExecutor=新的ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(10);
taskExecutor.setCorePoolSize(10);
taskExecutor.setQueueCapacity(10);
taskExecutor.AfterPropertieSet();
返回任务执行器;
}
@豆子
@步进镜
ItemReader xmlFileItemReader(@Value(“#{stepExecutionContext[fileName]}”)字符串文件名){
VtdWholeItemReader xmlFileReader=新VtdWholeItemReader();
setResource(新类路径资源(“输入/分区器/”+filename));
返回xmlFileReader;
}
@豆子
@步进镜
公共CustomMultiResourcePartitioner分区器(@Value(“#{jobParameters['fileName']}”)字符串文件名){
logger.info(
@Override
public void write(List<? extends List<Payment>> items) throws Exception {

    log.info("Items {}", items.size());
}
@Bean
@StepScope
VtdWholeItemReader<Payment> xmlFileItemReader(@Value("#{stepExecutionContext[fileName]}") String filename) {
   VtdWholeItemReader<Payment> xmlFileReader = new VtdWholeItemReader<>();
   xmlFileReader.setResource(new ClassPathResource("input/partitioner/" + filename));
   return xmlFileReader;
}