6

我正在尝试使用ListItemReader<String>,ItemProcessor<String, String>和创建 Spring Batch 作业ItemWriter<String>

XML 如下所示,

<job id="sourceJob" xmlns="http://www.springframework.org/schema/batch">
    <step id="step1" next="step2">
        <tasklet>
            <chunk reader="svnSourceItemReader" 
                processor="metadataItemProcessor" 
                writer="metadataItemWriter" 
                commit-interval="1" />
        </tasklet>
    </step>
    <step id="step2">
        <tasklet ref="lastRevisionLoggerTasklet"></tasklet>
    </step>
</job>

<bean id="svnSourceItemReader" 
        class="com.example.repository.batch.SvnSourceItemReader" 
        scope="prototype">
    <constructor-arg index="0">
        <list>
            <value>doc1.xkbml</value>
            <value>doc2.xkbml</value>
            <value>doc3.xkbml</value>
        </list>
    </constructor-arg>
</bean>

<bean id="metadataItemProcessor" 
        class="com.example.repository.batch.MetadataItemProcessor" 
        scope="prototype" />

<bean id="metadataItemWriter" 
        class="com.example.repository.batch.MetadataItemWriter" 
        scope="prototype" />

读取器、处理器和写入器是普通的,

public class SvnSourceItemReader extends ListItemReader<String> {

    public SvnSourceItemReader(List<String> list) {
        super(list);
        System.out.println("Reading data list " + list);
    }

    @Override
    public String read() {
        String out = (String) super.read();
        System.out.println("Reading data " + out);
        return out;
    }

}

public class MetadataItemProcessor implements ItemProcessor<String, String> {

    @Override
    public String process(String i) throws Exception {
        System.out.println("Processing " + i + " : documentId " + documentId);
        return i;
    }

}

public class MetadataItemWriter implements ItemWriter<String> {

    @Override
    public void write(List<? extends String> list) throws Exception {
        System.out.println("Writing " + list);
    }

}

作业是这样开始的,但每 10 秒安排一次。

long nanoBits = System.nanoTime() % 1000000L;
if (nanoBits < 0) {
    nanoBits *= -1;
}
String dateParam = new Date().toString() + System.currentTimeMillis() 
        + "." + nanoBits;
param = new JobParametersBuilder().addString("date", dateParam)
        .toJobParameters();
JobExecution execution = jobLauncher.run(job, param);

当应用程序启动时,我看到它读取、处理和写入传递给阅读器的列表中的三个项目。

Reading data doc1.xkbml
Processing doc1.xkbml : documentId doc1
Writing [doc1.xkbml]
Reading data doc2.xkbml
Processing doc2.xkbml : documentId doc2
Writing [doc2.xkbml]
Reading data doc3.xkbml
Processing doc3.xkbml : documentId doc3
Writing [doc3.xkbml]

因为这sourceJob是在预定的计时器上,所以我希望每 10 秒看到一次处理该列表,但我看到的是所有后续运行。

Reading data null

有谁知道为什么会这样?我是 Spring Batch 的新手,无法解决这个问题。

谢谢/w

4

2 回答 2

16

问题是您将阅读器标记为scope="prototype". 应该是scope="step"

在 Spring-batch 中只有两个作用域:(singleton默认)和step.

javadoc

StepScope
步骤上下文的范围。此范围内的对象使用 Spring 容器作为对象工厂,因此每个执行步骤只有一个此类 bean 的实例。此范围内的所有对象都是(无需装饰 bean 定义)。

为了使用后期绑定,需要使用 Step 的范围,因为在 Step 启动之前无法实际实例化 bean,这允许找到属性。

在 Spring 上下文启动期间,查看您的日志,您将看到以下行:

信息:在 9 毫秒内完成从类路径资源 [org/springframework/batch/core/schema-hsqldb.sql] 执行 SQL 脚本。
读取数据列表 [doc1.xkbml, doc2.xkbml, doc3.xkbml]

如您所见,您的阅读器已作为单例创建和管理;spring-batch 上下文中的动态 bean 应使用特殊step范围进行管理,以便 Spring 每次执行步骤时都会创建 bean 的新副本。

在您的阅读器中,ListItemReader.read()写为:

public T read() {
  if (!list.isEmpty()) {
    return list.remove(0);
  }
  return null;
}

在每个阅读项目中都从原始列表中删除!阅读器构建一次,在第二次作业执行时,列表为空!

于 2013-08-29T20:49:18.633 回答
4

只是附加信息:您还可以使用 JavaConfig 代替 xml 配置文件,并使用 @StepConfig 注释阅读器 bean 声明。

前任:

@Configuration
@EnableBatchProcessing
public class MyConfig {
...

    @Bean
    @StepScope
    public ItemReader<HeadingBreakevenAssociation> readerHeadingBreakevenAssociationList(){
         ItemReader<Person> itemReader = new ListItemReader<Person>(myList);

          return itemReader;
    }

}
于 2014-01-28T19:57:49.147 回答