简体   繁体   English

如何在spring-batch中将参数从ItemReader传递到ItemProcessor?

[英]How to pass parameters from ItemReader to ItemProcessor in spring-batch?

Question is simple: how can I pass a value that is only know within ItemReader (eg the current filename) to the ItemProcessor ? 问题很简单:如何将仅在ItemReader知道的值(例如当前文件名)传递给ItemProcessor

@Bean
@JobScope
public ItemReader<String> reader(@Value("#{jobParameters['path]}") String path) {
    FlatFileItemReader<String> delegate = new FlatFileItemReader<>();
    delegate.setLineMapper(new PassThroughLineMapper());

    Resource[] res = new PathMatchingResourcePatternResolver().getResources("file:" + path);

    MultiResourceItemReader<String> r = new MultiResourceItemReader<>();
    r.setResources(res);
    r.setDelegate(delegate);
    return r;
}

@Bean
public ItemProcessor<String, String> processor() {
    return new ItemProcessor<String, String>() {

        @Override
        public String process(String item) throws Exception {
            //TODO I need the filename that is currently processed. HOW?
            return null;
        }
    };
}

in order to be on the safe side, you should add the name of the file to the object that is returned by the reader. 为了安全起见,应将文件名添加到阅读器返回的对象中。 In order to do that, you have to implement your own wrapper Reader. 为此,您必须实现自己的包装阅读器。 Something like this: 像这样:

public class MyReader {
     private MultiResourceItemReader delegatereader;

     public MyContainerDto read() {
          String line = delegatereader.read();
          if (line==null) return null;

          Resource currentResource = delegatereader.getCurrentResource();

          MyContainerDto container = MyContainerDto();
          container.setLine(line);
          container.setResourceName(currentResource.getFileName());
          return container;
     }

     ...
} 

(this code was not tested, it just illustrates the aproach I would take) (此代码未经测试,仅说明了我要采取的方法)

On my laptop, I'm able to crate 1 million objects within a second, so the additional performance needed in order to create the objects isn't really something that affects the overall performance significantly. 在我的笔记本电脑上,我能够在一秒钟内创建100万个对象,因此创建对象所需的额外性能并不会真正影响整体性能。

The problem is, that the reader reads as many items, as is defined by the chunksize. 问题是,读取器读取的数据量与块大小定义的一样多。 After that, it will call the processor for every item in this chunk. 之后,它将为该块中的每个项目调用处理器。 Therefore, within a chunk, the items in it could have been read from different files. 因此,在一个块中,其中的各项可能已从其他文件中读取。 Hence, there is no other way than to bind the line and the filename together in the reader. 因此,除了在阅读器中将行和文件名绑定在一起,别无其他方法。

see also https://blog.codecentric.de/en/2012/03/transactions-in-spring-batch-part-1-the-basics/ 另请参阅https://blog.codecentric.de/zh/2012/03/transactions-in-spring-batch-part-1-the-basics/

It's probably best to introduce a dto for the reader. 最好为读者介绍一个dto。

public class ResourceAwareString implements ResourceAware {
     private String content;
     private Resource res;

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

Then the MultiResourceItemReader<ResourceAwareString> will automatically detect it and write the resource to the dto. 然后, MultiResourceItemReader<ResourceAwareString>将自动检测它并将资源写入dto。

Other approach would be to make both ItemReader and ItemProcessor @StepScope and use @BeforeStep to get access to the current StepExection context. 另一种方法是使ItemReaderItemProcessor @StepScope使用@BeforeStep来访问当前的StepExection上下文。 Then it's possible to set/get a value, and thereby transport values from reader to processer, or even to writer. 然后可以设置/获取值,从而将值从读取器传输到处理器,甚至传输到写入器。

Note that @BeforeStep only works on a public class, and NOT on an anonymous method like: 请注意, @BeforeStep仅适用于公共类, @BeforeStep用于匿名方法,例如:

new FlatFileItemReader<String>() {
  @BeforeStep
  public void before(StepExecution stepEx) {
       //this will never be called! don't do this.
  }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM