【问题标题】:Spring Batch: org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be readSpring Batch:org.springframework.batch.item.ReaderNotOpenException:阅读器必须打开才能读取
【发布时间】:2014-07-13 21:37:59
【问题描述】:

我阅读了与 SO 相关的问题,但解决方案对我不起作用。

我得到了org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read 异常。

下面是我的配置:

@Bean
@StepScope
public ItemReader<Player> reader(@Value("#{jobParameters[inputZipfile]}") String inputZipfile) {
                final String [] header = { .. this part omitted for brevity ... };
                FlatFileItemReader<Player> reader = new FlatFileItemReader<Player>();


                System.out.println("\t\t\t\t\t"+inputZipfile);

                reader.setResource(new ClassPathResource(inputZipfile));
                reader.setLineMapper(new DefaultLineMapper<Player>() {{
                    setLineTokenizer(new DelimitedLineTokenizer() {{
                        setNames( header );
                    }});
                    setFieldSetMapper(new BeanWrapperFieldSetMapper<Player>() {{
                        setTargetType(Player.class);
                    }});
                }});
                reader.setComments( header );
                return reader;
}

@Bean
@StepScope
public ItemProcessor<Player, PlayersStats> processor(@Value("#{jobParameters[statType]}") String statType,
                                                                 @Value("#{jobParameters[season]}") String season){
                PlayersStatsProcessor psp = new PlayersStatsProcessor();
                psp.setStatisticType( StatisticType.valueOf(statType) );
                psp.setSeason( season );
                return psp;
}


@Bean
@StepScope
public ItemWriter<PlayersStats> writer(){
            return new CustomWriter();
}


@Bean
public Job generateStatisticsJob() {

        return this.jobs.get("generateStatisticsJob")
                .incrementer(new RunIdIncrementer())
                .start(processPlayerStats())
                //.end()
                .build();
}

@Bean
public Step processPlayerStats() {
           return this.steps.get("processPlayerStats")        
                        .<Player, PlayersStats> chunk(10)
                        .reader(reader(null))
                        .processor(processor(null,null))
                        .writer(writer())
                        .build();
}

inputZipFile 变量设置正确并且文件存在于驱动器上。 我签入了 FlatFileItemReader 代码,当未设置阅读器类的阅读器成员时,会发生 ReaderNotOpenException。阅读器成员在 doOpen 方法中设置。 看起来 doOpen 没有被调用。问题是为什么?

【问题讨论】:

  • 但是 FlatFileItemReader 能够读取 zip 文件吗?
  • inputZipFile 是剩余的。我正在传递 txt 文件。

标签: java spring-batch


【解决方案1】:

当我将阅读器 bean 的返回类型从 Item 更改为 FlatFileItemReader 时,该问题消失了。我仍然不清楚为什么这是一个问题,因为 chunk().reader() 接受 ItemReader 作为输入。我假设在底层有一些 AOP 魔法,它执行 FlatFileReader 初始化并按返回类型匹配。

【讨论】:

  • 顺便说一句,Michael Minella 在这里解释了这个 AOP 魔法:stackoverflow.com/questions/21241683/…
  • 确实@StepScope 被定义为@Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)
【解决方案2】:

既然你把reader放在StepScope,那么bean返回类型应该是实现类型FlatFileItemReader

@Bean
@StepScope
public FlatFileItemReader<Player> reader(@Value("#{jobParameters[inputZipfile]}") String inputZipfile) {
            ...
            return reader;
}

如果指定接口,则Spring代理只能访问接口ItemReader上指定的方法和注解,缺少重要注解。日志中还有一个警告(有错字):

2015-05-07 10:40:22,733 WARN  [main] org.springframework.batch.item.ItemReader is an interface.  The implementing class will not be queried for annotation based listener configurations.  If using @StepScope on a @Bean method, be sure to return the implementing class so listner annotations can be used.
2015-05-07 10:40:22,748 WARN  [main] org.springframework.batch.item.ItemReader is an interface.  The implementing class will not be queried for annotation based listener configurations.  If using @StepScope on a @Bean method, be sure to return the implementing class so listner annotations can be used. 

目前 Spring Boot Batch 示例也返回了 ItemReader,所以我想其他人也会遇到同样的问题。

【讨论】:

  • 它对我有用。 1. 添加@StepScope 2. 对于返回类型为ItemReader、ItemWriter的每个ItemReader、ItemWriter方法,将返回类型更改为JdbcCursorItemReader、JdbcCursorItemWriter等实际实现类。另外,如果您有阅读器“关闭”的异常,请添加 @Bean(destroyMethod="")
【解决方案3】:

因为ItemReader没有open方法,使用hte StepScope会根据返回类型创建一个代理类。返回ItemStreamReader也可以

【讨论】:

    【解决方案4】:

    我已通过以下方式修复它:

    reader.open(new ExecutionContext());
    

    【讨论】:

    • 在挣扎了 1.5 天后,这实际上对我有用。
    • 这是一个坏技巧,不是正确的解决方案。如果您允许 Spring 自动调用 reader.open(),他会自动调用:您的 @Bean 方法必须按照其他答案的建议返回实现类。
    • 感谢这个 hack,我可以将 Chunk 步骤阅读器回收到 Tasklet 步骤中。
    【解决方案5】:

    我认为你应该在 processPlayerStats() step bean 类中增加你的块大小,即从块(10)到块(100/更多可能)。

    【讨论】:

      【解决方案6】:

      我定义的方法如下:

          @Bean
          @StepScope
          public ItemReader<BP> BPReader(){
             
              JdbcCursorItemReader<BP> itemReader = new JdbcCursorItemReader<BP>();
              ...
              return itemReader;
          }

      我在方法中定义的类型是ItemReader,它是一个接口,返回类型是JdbcCursorItemReader,它是它的一个子类。通过将返回类型定义更改为 JdbcCursorItemReader 解决了我的问题

      【讨论】:

        【解决方案7】:

        同样的问题。 将阅读器的返回类型更改为实际实现并添加到阅读器

        implements ItemStream
        

        帮我搞定了

        【讨论】:

          猜你喜欢
          • 2016-12-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-02
          • 1970-01-01
          • 1970-01-01
          • 2018-03-04
          相关资源
          最近更新 更多