Spring batch 同一批spring是否可以同时从不同的多线程调用不同的作业参数

Spring batch 同一批spring是否可以同时从不同的多线程调用不同的作业参数,spring-batch,Spring Batch,我们的要求是同时写入多个文件。我们使用spring批处理来编写文件,并且我们从不同的线程使用spring批处理。每个线程都有自己的应用程序上下文。因此,我们可以确保单音bean不会在多个线程之间共享。下面是我的代码片段 Spring批处理配置 <bean id="reportDataReader" class="com.test.ist.batch2.rrm.batch.readers.RRMItmeReader" scope="step"> <property

我们的要求是同时写入多个文件。我们使用spring批处理来编写文件,并且我们从不同的线程使用spring批处理。每个线程都有自己的应用程序上下文。因此,我们可以确保单音bean不会在多个线程之间共享。下面是我的代码片段

Spring批处理配置

<bean id="reportDataReader" class="com.test.ist.batch2.rrm.batch.readers.RRMItmeReader"
    scope="step">
    <property name="verifyCursorPosition" value="false" />
    <property name="dataSource" ref="dataSource" />
    <property name="sql" value="#{jobParameters['sqlquery']}" />
    <property name="rowMapper" ref="valueMapper" />
    <property name="fetchSize" value="5000" />
</bean>

<bean id="valueMapper" class="com.test.ist.batch2.rrm.batch.mappers.DBValueMapper" scope="step"></bean>

<bean id="velocityFileWritter"
    class="com.test.ist.batch2.rrm.batch.writers.RRMVelocityFileWriter"
    scope="step">
</bean>

<bean id="velocityEngine"
    class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
    <property name="velocityProperties">
        <value>
            resource.loader = class
            class.resource.loader.class = org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
            class.resource.loader.cache = true
            class.resource.loader.modificationCheckInterval = 0
        </value>
    </property>
</bean>

<batch:job id="rrmReportGenJob">
    <batch:step id="rrmReportGenStep">
        <batch:tasklet>
            <batch:chunk reader="reportDataReader" writer="velocityFileWritter"
                commit-interval="${reportData.reader.commit-interval}">
            </batch:chunk>
        </batch:tasklet>
    </batch:step>
</batch:job>

下面是我们如何调用spring批处理的代码摘录

Job jobToExecute=(Job)SpringUtils.getBean(jobName); JobParametersBuilder paramsBuilder=新的JobParametersBuilder(); //默认情况下,添加数据时间。这将有助于使用相同的参数再次启动相同的作业 paramsBuilder.addLong(“作业时间”,System.currentTimeMillis()); 如果(!jobParams.isEmpty()){ //验证输入字段。 字符串sqlToUse=validator.validateInput(jobParams); 对于(Map.Entry:jobParams.entrySet()){

如果它是在一个线程中运行的,则工作正常。 当它被多个线程调用时,我们会得到下面的错误

09:09:26742错误池-1-线程-3作业。抽象作业:329-执行作业时遇到致命错误 java.lang.NullPointerException 位于org.springframework.batch.core.repository.dao.MapJobExecutionDao.synchronizeStatus(MapJobExecutionDao.java:158) 位于org.springframework.batch.core.repository.support.SimpleJobRepository.update(SimpleJobRepository.java:161) 在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处 在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)中 在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)中 位于java.lang.reflect.Method.invoke(Method.java:606) 位于org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) 位于org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) 在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:157)上 位于org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98) 位于org.springframework.transaction.interceptor.TransactionSpectSupport.invokeWithinTransaction(TransactionSpectSupport.java:262) 位于org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95) 在org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:179)上 位于org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207) 位于com.sun.proxy.$Proxy14.update(未知源) 位于org.springframework.batch.core.job.AbstractJob.updateStatus(AbstractJob.java:416) 位于org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:299) 位于org.springframework.batch.core.launch.support.simplejoblancher$1.run(simplejoblancher.java:135) 位于org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) 位于org.springframework.batch.core.launch.support.simplejoblancher.run(simplejoblancher.java:128)


有谁能帮助我理解可能的错误吗?

你确定MapJobExecutionDao在所有方面都是线程安全的吗?我知道,在side MapJobExecutionDao中使用了ConcurrentMap,但我不确定这是否足够。我曾经在从不同线程访问的映射中获取空指针时遇到问题问题是,其中一个线程导致了重新灰化,而当第二个线程在那个时刻访问映射时,它收到了一个空指针

您确定标识jobparameters的组合是唯一的吗?我知道,您使用System.currentTimeMillis()添加了一个参数Job\u Time,但是您知道,如果这真的在唯一的时间戳中解决了吗


您是否尝试过使用基于表的JobExecutionDao等版本?

MapJobRepository不是用于生产的。它是线程安全的。如果您需要内存中作业存储库的性能(失去可重启性等),请使用内存中数据库,如HSQLDB

撇开这一点不谈,如果您使用的是线程安全组件,那么没有理由不能使用多个线程启动多个作业实例

public PetReportGenerator(ApplicationContext reportContext){
    if(null == reportContext){
        //if(null == appContext){
        appContext=new ClassPathXmlApplicationContext("spring-batch-jobs.xml");
        //}
    }else{
        setAppContext(reportContext);;
    }
}
                    paramsBuilder.addString(entry.getKey(), entry.getValue());

            }

        }else{
            throw new ReportGenerationException("Job input parameter is Empty");
        }

        jobexe=jobLauncher.run(jobToExecute, paramsBuilder.toJobParameters());