2010-02-18 3 views

Répondre

16

À partir d'une étape, vous pouvez mettre des données dans StepExecutionContext. Ensuite, avec un écouteur, vous pouvez promouvoir les données de StepExecutionContext à JobExecutionContext. Ce numéro JobExecutionContext est disponible dans toutes les étapes suivantes.

Attention: les données doivent être courtes. Ces contextes sont enregistrés dans le JobRepository par sérialisation et la longueur est limitée (2500 caractères si je me souviens bien). Par conséquent, ces contextes sont bons pour partager des chaînes ou des valeurs simples, mais pas pour partager des collections ou d'énormes quantités de données.

Le partage d'énormes quantités de données n'est pas la philosophie de Spring Batch. Spring Batch est un ensemble d'actions distinctes, pas une énorme unité de traitement d'affaires.

24

le dépôt de travail est utilisé indirectement pour transmettre des données entre les étapes (Jean-Philippe est juste que la meilleure façon de le faire est de mettre les données dans le StepExecutionContext puis utilisez le verbeux nommé ExecutionContextPromotionListener pour promouvoir les clés du contexte d'exécution de l'étape à . le JobExecutionContext

Il est utile de noter qu'il ya un écouteur pour la promotion de JobParameter clés à un StepExecutionContext aussi bien (le plus verbeux nommé JobParameterExecutionContextCopyListener), vous constaterez que vous utilisez ces beaucoup si vos étapes de travail ne sont pas complètement indépendants les uns des autres

Ot Par la suite, il vous reste à transmettre des données entre les étapes en utilisant des schémas encore plus élaborés, comme les files d'attente JMS ou les emplacements de fichiers codés en dur (interdits par Dieu).

Quant à la taille des données transmises dans le contexte, je suggère aussi que vous le garder petit (mais je n'ai pas de détails sur la

+3

Ceci est confirmé par la documentation + exemple ici: http://docs.spring.io/spring-batch/trunk/reference/html/patterns.html#passingDataToFutureSteps –

+0

Merde, cinq ans plus tard et cette question a encore de la traction. Way to go Spring Batch :) – WineSoaked

6

Vous pouvez utiliser un Java Bean objet

  1. Exécuter une étape
  2. stocker le résultat dans l'objet Java
  3. l'étape suivante confiera le même objet java pour obtenir le résultat enregistré par l'étape 1

De cette façon, vous pouvez stocker une énorme collection de données si vous voulez

+12

Dans la prochaine étape, comment vais-je obtenir l'objet de la 1ère étape. Tout le point de la question est que – Elbek

+2

@Elbek Autowire it. Votre classe à la première étape a le POJO autowired et définit les données, et votre classe à l'étape deux a également le même objet autowired (devrait être la même instance sauf si vous faites le partitionnement à distance) et utilise le getter. – IceBox13

+0

Comment avez-vous autowire une instance nouvellement créée à l'étape 1 de l'étape 2? Hiow attacher la nouvelle instance dans le contexte de printemps? – Chandru

4

Voici ce que j'ai fait pour enregistrer un objet qui est accessible à travers les étapes.

  1. créé un écouteur pour le réglage de l'objet dans le contexte de l'emploi
@Component("myJobListener") 
public class MyJobListener implements JobExecutionListener { 

    public void beforeJob(JobExecution jobExecution) { 

     String myValue = someService.getValue(); 
     jobExecution.getExecutionContext().putString("MY_VALUE", myValue); 
    } 
} 
  1. Défini l'auditeur dans le cadre de l'emploi
<listeners> 
     <listener ref="myJobListener"/> 
</listeners> 
  1. consommée la valeur dans l'étape en utilisant l'annotation BeforeStep
@BeforeStep 
public void initializeValues(StepExecution stepExecution) { 

String value = stepExecution.getJobExecution().getExecutionContext().getString("MY_VALUE"); 

} 
+1

Ce n'est pas thread-safe. – BrianC

12

Je dirais que vous avez 3 options:

  1. Utilisez StepContext et promouvoir à JobContext et vous y avoir accès à partir de chaque étape, vous devez, comme indiqué limite obey taille
  2. Créer @JobScope bean et ajouter des données à ce haricot, @Autowire si nécessaire et l'utiliser (l'inconvénient est que c'est la structure en mémoire et si le travail échoue, les données sont perdues, peut causer des problèmes de redémarrage)
  3. Nous avions des ensembles de données plus importants à traiter (lire chaque ligne dans csv et écrire dans DB, lire à partir de DB, agréger et envoyer à API) afin de modéliser les données dans une nouvelle table. , gardez ids dans JobContext et accédez si nécessaire et supprimez cette table temporaire lorsque le travail se termine avec succès.
+2

En ce qui concerne votre option 2. Puis-je accéder à un ensemble de beans à partir de classe de lecteur de classe d'écrivain de cette manière? –

+0

Comment voulez-vous définir à partir du lecteur? Nous avons créé le bean en dehors de la configuration et l'avons injecté si nécessaire. Vous pouvez essayer et voir comment promouvoir quelque chose du lecteur à la portée de l'emploi, mais il me semble étrange de définir quelque chose avec la portée du travail dans le lecteur. –

1

J'ai reçu une tâche pour appeler le travail par lots un par un. Chaque travail dépend d'un autre. Le premier résultat du travail doit exécuter le programme de travail qui en découle. Je cherchais comment transmettre les données après l'exécution du travail. J'ai trouvé que cette ExecutionContextPromotionListener est pratique.

1) J'ai ajouté un haricot pour "ExecutionContextPromotionListener" comme ci-dessous

@Bean 
public ExecutionContextPromotionListener promotionListener() 
{ 
    ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener(); 
    listener.setKeys(new String[] { "entityRef" }); 
    return listener; 
} 

2) Ensuite, j'attaché un de l'auditeur à mes pas

Step step = builder.faultTolerant() 
      .skipPolicy(policy) 
      .listener(writer) 
      .listener(promotionListener()) 
      .listener(skiplistener) 
      .stream(skiplistener) 
      .build(); 

3) J'ai ajouté stepExecution comme une référence dans mon implémentation d'étape Writer et peuplée dans le Beforestep

@BeforeStep 
public void saveStepExecution(StepExecution stepExecution) 
{ 
    this.stepExecution = stepExecution; 
} 

4) dans la fin de mon étape écrivain, je peuplé les valeurs du stepexecution comme les touches comme ci-dessous

lStepContext.put("entityRef", lMap); 

5) Après l'exécution du travail, je récupérai les valeurs de la lExecution.getExecutionContext() et peuplé comme réponse d'emploi. 6) à partir de l'objet de réponse de travail, j'obtiendrai les valeurs et remplirai les valeurs requises dans le reste des travaux.

Le code ci-dessus permet de promouvoir les données des étapes vers ExecutionContext à l'aide de ExecutionContextPromotionListener. Il peut être fait pour toutes les étapes.

1

Utilisez `ExecutionContextPromotionListener.

public class YourItemWriter implements ItemWriter<Object> { 
private StepExecution stepExecution; 
public void write(List<? extends Object> items) throws Exception { 
// Some Business Logic 

// put your data into stepexecution context 
ExecutionContext stepContext = this.stepExecution.getExecutionContext(); 
stepContext.put("someKey", someObject); 
} 
@BeforeStep 
public void saveStepExecution(Final StepExecution stepExecution) { 
this.stepExecution = stepExecution; 
} 
} 

Maintenant, vous devez ajouter promotionListener à votre travail

@Bean 
public Step step1() { 
     return stepBuilder 
     .get("step1")<Company,Company> chunk(10) 
     .reader(reader()).processor(processor()).writer(writer()) 
     .listener(promotionListner()).build(); 
    } 

@Bean publique ExecutionContextPromotionListener promotionListner() { ExecutionContextPromotionListener listner = new ExecutionContextPromotionListener(); listner.setKeys (new String [] {"someKey"}); listner.setStrict (true); liste de retour; }

Maintenant, à l'étape 2 obtenir vos données de travail ExecutionContext

public class RetrievingItemWriter implements ItemWriter<Object> { 
private Object someObject; 
public void write(List<? extends Object> items) throws Exception { 
// ... 
} 
@BeforeStep 
public void retrieveInterstepData(StepExecution stepExecution) { 
JobExecution jobExecution = stepExecution.getJobExecution(); 
ExecutionContext jobContext = jobExecution.getExecutionContext(); 
this.someObject = jobContext.get("someKey"); 
} 
} 

Si vous travaillez avec tasklets, puis utilisez follwing pour obtenir ou mettre ExecutionContext

List<YourObject> yourObjects = (List<YourObject>) chunkContent.getStepContext().getJobExecutionContext().get("someKey"); 
Questions connexes