Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JobParameters from Spring Batch

I am trying to inject job parameters into a custom ItemReader. I have reviewed all of the StackOverflow notes on the subject (example: How to get access to job parameters from ItemReader, in Spring Batch?), and I see this is a common pain point that is mostly unresolved. I am hoping that a spring guru (@Michael Minella anyone) will see this and have some insight.

I have got as far as determining that the jobparameters are available about one out of 10 runs, even with no code or configuration changes. This is a case of a random success rather than a random failure, so it's proving hard to track down.

I dug into the spring code with the debugger, and determined that when this fails, no bean of the name jobParameters is registered in Spring at the time that the injection is taking place.

I am using Spring 4.1.4 with spring-batch 3.0.2 and spring-data-jpa 1.7.1 and spring-data-commons 1.9.1, running in java 8.

Java class

@Component("sourceSelectionReader")
@Scope("step")
public class SourceSelectionReaderImpl  
implements ItemReader<MyThing> {
    private Map<String,Object> jobParameters;

// ... snip ...


    @Autowired
    @Lazy
    @Qualifier(value="#{jobParameters}")
    public void setJobParameters(Map<String, Object> jobParameters) {
        this.jobParameters = jobParameters;
    }
}

Job launch parameters:

launch-context.xml job1 jobid(long)=1

launch-context.xml (minus the fluff):

<context:property-placeholder location="classpath:batch.properties" />

<context:component-scan base-package="com.maxis.maximo.ilm" />

<jdbc:initialize-database data-source="myDataSource"  enabled="false">
    <jdbc:script location="${batch.schema.script}" />
</jdbc:initialize-database>

<batch:job-repository id="jobRepository" 
    data-source="myDataSource"
    transaction-manager="transactionManager"
    isolation-level-for-create="DEFAULT"
    max-varchar-length="1000"/>

<import resource="classpath:/META-INF/spring/module-context.xml" />

Module-context.xml (minus the fluff):

<description>Example job to get you started. It provides a skeleton for a typical batch application.</description>

<import resource="classpath:/META-INF/spring/hibernate-context.xml"/>
<import resource="classpath:/META-INF/spring/myapp-context.xml"/>

<context:component-scan base-package="com.me" />
<bean class="org.springframework.batch.core.scope.StepScope" />

<batch:job id="job1">
    <batch:step id="step0002"  >            
        <batch:tasklet transaction-manager="transactionManager" start-limit="100" >
            <batch:chunk reader="sourceSelectionReader" writer="selectedDataWriter" commit-interval="1" />
        </batch:tasklet>
    </batch:step>
</batch:job> 
like image 801
pojo-guy Avatar asked Jan 09 '15 13:01

pojo-guy


People also ask

How do I run a specific job in Spring Batch?

Spring Batch auto configuration is enabled by adding @EnableBatchProcessing (from Spring Batch) somewhere in your context. By default it executes all Jobs in the application context on startup (see JobLauncherCommandLineRunner for details). You can narrow down to a specific job or jobs by specifying spring. batch.

What is Jobbuilderfactory in Spring Batch?

public JobBuilder get(java.lang.String name) Creates a job builder and initializes its job repository. Note that if the builder is used to create a @Bean definition then the name of the job and the bean name might be different. Parameters: name - the name of the job Returns: a job builder.

What is JobRepository in Spring Batch?

What is a "Job Repository" in Spring Batch? "JobRepository" is the mechanism in Spring Batch that makes all this persistence possible. It provides CRUD operations for JobLauncher, Job, and Step instantiations.

What is Spring Batch JobLauncher?

public interface JobLauncher. Simple interface for controlling jobs, including possible ad-hoc executions, based on different runtime identifiers. It is extremely important to note that this interface makes absolutely no guarantees about whether or not calls to it are executed synchronously or asynchronously.


1 Answers

The important steps to get Job Parameters to work is to define the StepScope bean and to make sure that your reader is a @StepScope component.

I would try the following:

First make sure that there is a step-bean defined. This is nice to setup using Java Configuration:

@Configuration
public class JobFrameworkConfig {  
    @Bean
    public static StepScope scope() {
        return new StepScope();
    }
    // jobRegistry, transactionManager etc...
}

Then, make sure that your bean is step-scoped by the use of the @StepScope-annotation (almost as in your example). Inject a @Value that is not @Lazy.

@Component("sourceSelectionReader")
@StepScope // required, also works with @Scope("step")
public class SourceSelectionReaderImpl implements ItemReader<MyThing> {
    private final long myParam;

    // Not lazy, specified param name for the jobParameters
    @Autowired
    public SourceSelectionReaderImpl(@Value("#{jobParameters['myParam']}") final long myParam) {
        this.myParam = myParam;
    }

    // the rest of the reader...
}
like image 80
wassgren Avatar answered Sep 28 '22 06:09

wassgren