【问题标题】:How to get access to job parameters from ItemReader, in Spring Batch?如何在 Spring Batch 中从 ItemReader 访问作业参数?
【发布时间】:2018-10-18 05:24:59
【问题描述】:

这是我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 中这些机制的信息?

【问题讨论】:

    标签: java spring spring-batch


    【解决方案1】:

    如前所述,您的阅读器需要在“步骤”范围内。您可以通过 @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 documentation,将以下内容添加到您的 Spring 配置中将使范围可用:

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

    【讨论】:

    • StepScope 现在默认可用
    • 从 v2.2 开始还有一个快捷方式,使用 @StepScope 和 @Bean
    • @Scope("step") 对我不起作用,而 @StepScope 对我有用
    • Spring 不太喜欢 final 类
    • 我们可以在方法上注释@StepScope
    【解决方案2】:

    如果您想在单个 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

    【讨论】:

    • 我们将如何测试这个?
    【解决方案3】:

    很晚了,但您也可以通过注释@BeforeStep 方法来做到这一点:

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

    【讨论】:

    • 这只有在作业参数的使用不改变ItemReader的状态时才有用。如果他们是例如用于指定要读取的数据,然后读取器的并发执行可能会导致错误的行为。
    • @tveon,这可以通过在声明 reader bean 时使用 StepScope 来解决,对吧?
    • @Kajzer 是的,除非你以后在同一个工作中重复使用阅读器,否则你也可以用JobScope解决它
    【解决方案4】:

    为了能够使用 jobParameters,我认为您需要将您的阅读器定义为范围“步骤”,但我不确定您是否可以使用注释来做到这一点。

    使用 xml-config 会变成这样:

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

    Spring Batch documentation 上进一步了解。

    也许它可以通过使用@Scope 并在您的 xml-config 中定义步骤范围来工作:

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

    【讨论】:

    • 我对注释特别感兴趣。这种配置格式是旧的和记录的。
    • 您没有声明您只对仅注释的解决方案感兴趣。无论如何感谢您的投票。
    【解决方案5】:

    补充一个额外的例子,你可以访问JavaConfig类中的所有作业参数:

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

    【讨论】:

      【解决方案6】:

      在执行作业时,我们需要传递 Job 参数如下:

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

      通过使用表达式语言,我们可以按如下方式导入值:

       #{jobParameters['file.name']}
      

      【讨论】:

        【解决方案7】:

        您是否将作业参数正确地声明为 bean?

        或者您是否意外实例化了一个没有文件名 getter 的 JobParameters 对象?

        有关表达式语言的更多信息,您可以在 Spring 文档here 中找到信息。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-06-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-29
          • 1970-01-01
          • 2015-11-25
          • 1970-01-01
          相关资源
          最近更新 更多