问题
I'm trying to pass an object between batchlets, but I've encountered a problem when trying to access the jobContext from a partitioned step (batchlet).
According to the JSR 352 Specification
9.4.1.1 Batch Context Lifecycle and Scope: A batch context has thread affinity and is visible only to the batch artifacts executing on that particular thread. A batch context injected field may be null when out of scope. Each context type has a distinct scope and lifecycle as follows: 1. JobContext There is one JobContext per job execution. It exists for the life of a job. There is a distinct JobContext for each sub-thread of a parallel execution (e.g. partitioned step). 2. StepContext There is one StepContext per step execution. It exists for the life of the step. For a partitioned step, there is one StepContext for the parent step/thread; there is a distinct StepContext for each sub-thread.
My (failed) solution was to use the JobContext.setTransientUserData, but because the partitioned step uses a distinct JobContext I can't get the TransientUserData.
Is there an alternative to what I'm trying to do? Using PartitionMapper properties it's not possible because I need to pass an object, not a string to every partition.
To be clear, I need to do this:
- NormalBatchlet -> Save an object to be used in the next step.
- PartitionedBatchlet -> Obtain the saved object in previous step. This object isn't a simple String so using PartitionMapper properties is not a solution.
UPDATE
I'm now using a simple Singleton EJB with a HashMap to store objects between steps and when the job is finished I clear this map to avoid resources leak.
This is a workaround because I really want to use only the javax.batch package and not depend on EJB's, so I'm not putting it as an answer.
回答1:
You could try something like this which should conform with the current spec programming model.
Store the object from your first step using the persistent step data in your NormalBatchlet:
stepCtx.setPersistentUserData(mySerializableData);
Retrieve the data from the first step in your partitions, by looking up the previous step:
Long execId = jobCtx.getExecutionId();
List<StepExecution> stepExecs = jobOperator.getStepExecutions(execID);
MyPersistentUserData myData;
for (StepExecution step : stepExecs) {
if (step.getStepName().equals("somePreviousStepX") {
myData = (MyPersistentUserData)step.getPersistentUserData();
}
}
//use myData
回答2:
There is not a spec-defined way to share the transient user data between the JobContext of the main thread and the partition-level JobContext(s). This is an understandable point of confusion, but this is indeed the intended design.
回答3:
In specification mentioned an only one way to access to Context - Injection. See paragraph 9.4.1.
"9.4.1 Batch Contexts
Batch artifact access to batch contexts is by injection using the standard @Inject annotation (javax.inject.Inject). A field into which a batch context is injected must not be static and must not be final.
E.g.:
@Inject JobContext _jctxt;
@Inject StepContext _sctxt;
The batch runtime is responsible to ensure the correct context object is injected according to the job or step currently executing."
来源:https://stackoverflow.com/questions/22306200/accesing-jobcontext-from-a-partitioned-step-in-jsr-352