如何在Spring Batch的ItemReader中获取作业参数的访问权限?

83

这是我的job.xml的一部分:

<job id="foo" job-repository="job-repository">
  <step id="bar">
    <tasklet transaction-manager="transaction-manager">
      <chunk commit-interval="1"
        reader="foo-reader" writer="foo-writer"
      />
    </tasklet>
  </step>
</job>

这是项目读取器:

import org.springframework.batch.item.ItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("foo-reader")
public final class MyReader implements ItemReader<MyData> {
  @Override
  public MyData read() throws Exception {
    //...
  }
  @Value("#{jobParameters['fileName']}")
  public void setFileName(final String name) {
    //...
  }
}

这是Spring Batch在运行时所说的:

Field or property 'jobParameters' cannot be found on object of 
type 'org.springframework.beans.factory.config.BeanExpressionContext'

这里有什么问题?我在哪里可以阅读更多关于Spring 3.0中这些机制的内容?

10个回答

84

正如所述,您的读取器需要是“step”范围。您可以通过@Scope("step")注释来实现这一点。如果您将该注释添加到您的读取器中,它应该对您有用,如下所示:

import org.springframework.batch.item.ItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("foo-reader")
@Scope("step")
public final class MyReader implements ItemReader<MyData> {
  @Override
  public MyData read() throws Exception {
    //...
  }

  @Value("#{jobParameters['fileName']}")
  public void setFileName(final String name) {
    //...
  }
}

默认情况下,这个作用域是不可用的,但如果使用了batch XML命名空间,它将可用。 如果没有,请根据Spring Batch文档,将以下内容添加到您的Spring配置中以使范围可用:

<bean class="org.springframework.batch.core.scope.StepScope" />

10
StepScope 现在已默认可用。 - Zarathustra
1
自v2.2版本开始,还有一种快捷方式,使用带有@Bean的@StepScope。 - Guillaume Husta
@Scope("step") 对我没用,而 @StepScope 有用。 - PixelMaster
Spring并不喜欢final类。 - gstackoverflow
我们可以在方法上注释@StepScope。 - Vishal Akkalkote

32

如果你想在单个JavaConfig类中定义ItemReader实例和Step实例。你可以使用@StepScope@Value注释,例如:

@Configuration
public class ContributionCardBatchConfiguration {

   private static final String WILL_BE_INJECTED = null;

   @Bean
   @StepScope
   public FlatFileItemReader<ContributionCard> contributionCardReader(@Value("#{jobParameters['fileName']}")String contributionCardCsvFileName){

     ....
   }

   @Bean
   Step ingestContributionCardStep(ItemReader<ContributionCard> reader){
         return stepBuilderFactory.get("ingestContributionCardStep")
                 .<ContributionCard, ContributionCard>chunk(1)
                 .reader(contributionCardReader(WILL_BE_INJECTED))
                 .writer(contributionCardWriter())
                 .build();
    }
}

关键是将空值传递给itemReader,因为它将通过@Value("#{jobParameters['fileName']}")注释进行注入。
感谢Tobias Flohre的文章:Spring Batch 2.2 – JavaConfig Part 2: JobParameters, ExecutionContext and StepScope

我们将如何测试这个? - RBz

21

这个方法有点晚了,但你也可以通过注释@BeforeStep方法来实现:

@BeforeStep
    public void beforeStep(final StepExecution stepExecution) {
        JobParameters parameters = stepExecution.getJobExecution().getJobParameters();
        //use your parameters
}

11
仅当作业参数的使用不改变ItemReader状态时,此功能才有用。如果例如使用它们来指定要读取的数据,则读取器的并发执行可能会导致不正确的行为。 - tveon
@tveon,这个问题可以通过在声明reader bean时使用StepScope来解决,对吗? - Kajzer
@Kajzer 是的,除非您在同一作业中稍后重新使用读取器,否则您也可以使用 JobScope 解决它。 - tveon

14

我认为要使用jobParameters,您需要将您的reader定义为“step”范围,但我不确定是否可以使用注释来完成此操作。

如果使用xml-config,则应该按以下方式进行:

<bean id="foo-readers" scope="step"
  class="...MyReader">
  <property name="fileName" value="#{jobExecutionContext['fileName']}" />
</bean>

请参见Spring Batch文档了解更多信息。

也许可以通过使用@Scope并在xml配置中定义步骤范围来实现:

<bean class="org.springframework.batch.core.scope.StepScope" />

我特别关注注解。这种配置格式已经过时并有文档记录。 - yegor256
你并没有说明你只对注解解决方案感兴趣。不管怎样,还是谢谢你的支持。 - abalogh

5

除此之外,您可以在JavaConfig类中访问所有作业参数,以下是附加示例:

@Bean
@StepScope
public ItemStreamReader<GenericMessage> reader(@Value("#{jobParameters}") Map<String,Object> jobParameters){
          ....
}

2

在执行任务时,我们需要按以下方式传递作业参数:

JobParameters jobParameters= new JobParametersBuilder().addString("file.name", "filename.txt").toJobParameters();   
JobExecution execution = jobLauncher.run(job, jobParameters);  

通过使用表达式语言,我们可以按以下方式导入值:
 #{jobParameters['file.name']}

0

技术性写作。

配置类。

    @Autowired
    @Qualifier("testReader")
    private testReader reader;


    @Bean(name = "testJob")
    public Job testJob(@Autowired @Qualifier("testStep") Step step) {
        return jobBuilderFactory
                .get("testJob")
                .incrementer(new RunIdIncrementer())
//                .listener(new JobCompletionListener())
                .start(step)
                .build();

    }

    @Bean("testStep")
    @JobScope
    public Step testStep(@Value("#{jobParameters['key']}") String key) {
        return stepBuilderFactory.get("testStep")
                .<UniqueUserVO, List<UniqueUser>>chunk(500)
                .reader(reader.setKey(key).reader())
                .processor(processor.processor())
                .writer(writer.writer())
                .build();

    }

读者接口类。

public interface Reader<T> {

    /**
     * reader 
     * @return
     */
    ItemReader<T> reader();
}

读者类

@Component
public class TestReader implements Reader<UniqueUserVO> {
    private String key;

    public TestReader setKey(String key) {
        this.key= key;
        return this;
    }
    @Override
    public ItemReader<UniqueUserVO> reader() {
       xxxxx
    }
}


-1

这可能是一种更简单的方法:

@Configuration
@Setter
@StepScope
public  class Reader extends FlatFileItemReader<Object> {

public Reader(@Value("#{jobParameters['filePath']}") String resource){
    setResource(new FileSystemResource(resource));
   }

}

-1

您可以在使用@BeforeStep注释的方法中,使用StepExecution上下文来获取作业参数并将其设置为变量,然后您可以在read方法中使用它。

在我的情况下,我编写了以下内容:

@Component
@RequiredArgsConstructor
public class SpelItemReader implements ItemReader<BatchRequest>{

private String requestId;


@Override
public BatchRequest read() {
   //access the request-id variable here
}

@BeforeStep
public void beforeStep(StepExecution stepExecution) {
    requestId = stepExecution.getJobParameters().getString("requestId");
}

}


-3

你是否将作业参数声明为Map并正确地定义为Bean?

或者你是否意外地实例化了一个JobParameters对象,该对象没有文件名的getter方法?

有关表达式语言的更多信息,请参阅Spring文档此处


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接