web-dev-qa-db-fra.com

Comment accéder aux paramètres de travail à partir de ItemReader, dans Spring Batch?

Cela fait partie de mon 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>

C'est le lecteur d'objet:

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) {
    //...
  }
}

Voici ce que dit Spring Batch au moment de l'exécution:

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

Quel est le problème ici? Où puis-je en savoir plus sur ces mécanismes dans Spring 3.0?

65
yegor256

Comme il a été dit, votre lecteur doit avoir une "portée". Vous pouvez accomplir cela via l'annotation @Scope("step"). Cela devrait fonctionner pour vous si vous ajoutez cette annotation à votre lecteur, comme suit:

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) {
    //...
  }
}

Cette étendue n'est pas disponible par défaut, mais le sera si vous utilisez l'espace de noms XML batch. Si vous ne l'êtes pas, l'ajout des éléments suivants à votre configuration Spring rendra la portée disponible, conformément à la documentation Spring Batch :

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

Si vous souhaitez définir votre instance ItemReader et votre instance Step dans une seule classe JavaConfig. Vous pouvez utiliser les @StepScope et les @Value annotations telles que:

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

L'astuce consiste à transmettre une valeur null à l'itemReader puisqu'il sera injecté via l'annotation @Value("#{jobParameters['fileName']}").

Merci à Tobias Flohre pour son article: Spring Batch 2.2 - JavaConfig, partie 2: JobParameters, ExecutionContext et StepScope

19
Ortomala Lokni

Pour pouvoir utiliser les paramètres jobParameters, je pense que vous devez définir votre lecteur comme une "étape" de la portée, mais je ne suis pas sûr que vous puissiez le faire en utilisant des annotations.

En utilisant xml-config, cela ressemblerait à ceci:

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

Voir plus loin le documentation Spring Batch .

Peut-être que cela fonctionne en utilisant @Scope et définissant l’étendue de l’étape dans votre configuration xml:

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

Assez tard, mais vous pouvez aussi le faire en annotant une méthode @BeforeStep:

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

Complétez avec un exemple supplémentaire, vous pouvez accéder à tous les paramètres de travail de la classe JavaConfig:

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

Lors de l'exécution du travail, nous devons transmettre les paramètres du travail comme suit:

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

en utilisant le langage d'expression, nous pouvons importer la valeur comme suit:

 #{jobParameters['file.name']}
1
Premraj