Skip to content

improve JobParameters to Non ThreadLocal #4644

Open
@thxwelchs

Description

@thxwelchs

JobParameters are managed by org.springframework.batch.core.scope.context.SynchronizationManagerSupport#executionHolder using ThreadLocal, which prevents SpEL bindings (@Value("#{jobParameters['param']}")) from working correctly in other threads.

However, JobParameters are typically read-only and do not change during batch execution. In a multi-threaded step (TaskExecutor), this ThreadLocal management causes access to JobParameters within JobScope or StepScope beans to fail.

I’m not sure why JobParameters need to be managed within a ThreadLocal JobContext. Could JobParameters be modified to be non-ThreadLocal instead?

I’m using a class that encapsulates JobParameters. However, access to this class's fields fails when accessed within a JobScope (or StepScope) bean in a multi-threaded step.

encapsulates JobParameters

@JobScope
@Component
public class MyJobParameters {

    @Value("#{jobParameters['firstParam']}")
    private String firstParam;

    @Value("#{jobParameters['secondParam']}")
    private String secondParam;

    public String getFirstParam() {
        return firstParam;
    }

    public String getSecondParam() {
        return secondParam;
    }
}

failed (multi thread step)

    public Step myMultiThreadStep() {
        return new StepBuilder("chunkWorkingStep", jobRepository)
                .<Sample, Sample>chunk(500, new ResourcelessTransactionManager())
                .reader(myReader())
                .processor(myProcessor())
                .writer(myWriter())
                .taskExecutor(taskExecutor())
                .build();
    }
    
    public ItemProcessor<Sample, Sample> myProcessor() {
        String firstParam = myJobParameters.getFirstParam(); // failed
        return item -> {
                   String secondParam = myJobParameters.getSecondParam(); // failed
            return item;
        };
    }

ok (non multi thread step)

    public Step myStep() {
        return new StepBuilder("chunkWorkingStep", jobRepository)
                .<Sample, Sample>chunk(500, new ResourcelessTransactionManager())
                .reader(myReader())
                .processor(myProcessor())
                .writer(myWriter())
                .build();
    }
    
    public ItemProcessor<Sample, Sample> myProcessor() {
        String firstParam = myJobParameters.getFirstParam(); // ok
        return item -> {
                   String secondParam = myJobParameters.getSecondParam(); // ok
            return item;
        };
    }

If there’s anything I might be missing or not understanding, please let me know.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: waiting-for-reporterIssues for which we are waiting for feedback from the reporter

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions