springenthusiast
springenthusiast

Reputation: 447

Why Spring batch executing as singleton instead of multithread

I am invoking a spring batch job through quartz scheduler, which should run every 1 minute. When the job runs the first time, the ItemReader is opened successfully and the job runs. However when the job attempts to run a second time, it's using the same instance it did the first time which is already initialized and receiving "java.lang.IllegalStateException: Stream is already initialized. Close before re-opening." I have set scope as step for both itemreader and itemwriter.

Please let me know if I am doing anything wrong in configuration?

<?xml version="1.0" encoding="UTF-8"?>

<import resource="context.xml"/>
<import resource="database.xml"/>   
<bean id="MyPartitioner" class="com.MyPartitioner" />
<bean id="itemProcessor" class="com.MyProcessor" scope="step" />

<bean id="itemReader" class="com.MyItemReader" scope="step">
    <property name="dataSource" ref="dataSource"/>
    <property name="sql" value="query...."/>
    <property name="rowMapper">
        <bean class="com.MyRowMapper" scope="step"/>
    </property>
</bean>

<job id="MyJOB" xmlns="http://www.springframework.org/schema/batch">
    <step id="masterStep">
        <partition step="slave" partitioner="MyPartitioner">
            <handler grid-size="10" task-executor="taskExecutor"/>
        </partition>
    </step>
</job>
<step id="slave" xmlns="http://www.springframework.org/schema/batch">
    <tasklet>
        <chunk reader="itemReader" writer="mysqlItemWriter" processor="itemProcessor" commit-interval="100"/>
    </tasklet>
</step>

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="20"/>
    <property name="maxPoolSize" value="20"/>
    <property name="allowCoreThreadTimeOut" value="true"/>
</bean>

<bean id="mysqlItemWriter" class="com.MyItemWriter" scope="step">
    <property name="dataSource" ref="dataSource"/>
    <property name="sql">
        <value>
            <![CDATA[      
            query.....
        ]]>
        </value>
    </property>

<property name="itemPreparedStatementSetter">
        <bean class="com.MyPreparedStatementSetter" scope="step"/>
    </property>
</bean>

Quartz job invoker-

Scheduler scheduler = new    StdSchedulerFactory("quartz.properties").getScheduler();
JobKey jobKey = new JobKey("QUARTZJOB", "QUARTZJOB");
JobDetail jobDetail =     JobBuilder.newJob("com.MySpringJobInvoker").withIdentity(jobKey).build();
jobDetail.getJobDataMap().put("jobName", "SpringBatchJob");
SimpleTrigger smplTrg = newTrigger().withIdentity("QUARTZJOB", "QUARTZJOB").startAt(new Date(startTime))  
                            .withSchedule(simpleSchedule().withIntervalInSeconds(frequency).withRepeatCount(repeatCnt))
                            .forJob(jobDetail).withPriority(5).build();
scheduler.scheduleJob(jobDetail, smplTrg);

Quartz job -

public class MySpringJobInvoker implements Job
{
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException
{
    JobDataMap data = jobExecutionContext.getJobDetail().getJobDataMap();

    ApplicationContext applicationContext =ApplicationContextUtil.getInstance();

    JobLauncher jobLauncher = (JobLauncher) applicationContext.getBean("jobLauncher");
    org.springframework.batch.core.Job job = (org.springframework.batch.core.Job) applicationContext.getBean(data.getString("jobName"));
    JobParameters param = new JobParametersBuilder().addString("myparam","myparam").addString(Long.toString(System.currentTimeMillis(),Long.toString(System.currentTimeMillis())).toJobParameters();
    JobExecution execution = jobLauncher.run(job, param);
}

}

Singletonclass -

public class ApplicationContextUtil {
private static ApplicationContext applicationContext;

public static synchronized ApplicationContext getInstance()
{
    if(applicationContext == null)
    {
        applicationContext = new ClassPathXmlApplicationContext("myjob.xml");
    }
    return applicationContext;
}

}

Upvotes: 1

Views: 2030

Answers (1)

Saifuddin Merchant
Saifuddin Merchant

Reputation: 1171

what are the parameters that you are passing to the Spring Batch job from Quartz? Could you post the exception stack trace?

If your trying to execute the second instance of the batch with the same parameters - it won't work. Spring Batch identifies a unique instance of the job based on parameters passed - so every new instance of the job requires different parameters to be passed.

Upvotes: 1

Related Questions