Java Spring Batch:org.springframework.batch.item.ReaderNotOpenException:阅读器必须打开才能被读取

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23847661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 01:33:06  来源:igfitidea点击:

Spring Batch: org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be read

javaspring-batch

提问by Luke

I read SO related questions but the solutions don't work for me.

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

I get the org.springframework.batch.item.ReaderNotOpenException: Reader must be open before it can be readexception.

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

Below is my configuration:

下面是我的配置:

@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();
}

The inputZipFile variable is set properly and the file exists on the drive. I checked in the FlatFileItemReader code and the ReaderNotOpenException occurs when the reader member of the reader class is not set. The reader member is set in doOpen method. It looks that doOpen is not called. The question is why ?

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

回答by Luke

The issue disappeared when I change the return type of my reader bean from Item to FlatFileItemReader. It is still not clear to me why this is a problem since chunk().reader() accepts ItemReader as an input. I assume that there is some AOP magic under the hood which does FlatFileReader init and matches by the return type.

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

回答by user3871744

It is because ItemReader don't have the open method, using hte StepScope will create a proxy class based on the return type. It is also ok to return ItemStreamReader

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

回答by Nick Vanderhoven

Since you put the reader in StepScope, the bean return type should be the implementing type FlatFileItemReader:

由于您将读取器放入StepScope,bean 返回类型应该是实现类型FlatFileItemReader

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

If you specify the interface, the Spring proxy only has access to the methods and annotations specified on the interface ItemReaderand is missing important annotations. There is also a warning (with a typo) in the logs:

如果指定了接口,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. 

Currently the Spring Boot Batch example is also returning the ItemReader, so I guess other people will struggle with the same issues.

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

回答by bodtx

Same problem here. Changing return type of my reader to the real implementation and adding to the reader

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

implements ItemStream

Did the trick for me

对我有用

回答by Kiran Kumar

I think you should increase your chunk size in processPlayerStats() step bean class, i.e from chunk(10) to chunk(100/more may be).

我认为您应该在 processPlayerStats() 步骤 bean 类中增加块大小,即从 chunk(10) 到 chunk(100/more 可能是)。

回答by Amitabha Roy

I have fixed it by:

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

reader.open(new ExecutionContext());

回答by Ray

The method I defined is like below:

我定义的方法如下:

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

The type I defined in the method is ItemReader which is an interface, the return type is JdbcCursorItemReader which is a sub-class of it. By changing the return type defination to JdbcCursorItemReader solved my problem

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