Java Spring批处理JdbcPagingItemReader未正确初始化,因为它未正确关闭

Java Spring批处理JdbcPagingItemReader未正确初始化,因为它未正确关闭,java,spring,spring-batch,Java,Spring,Spring Batch,我需要扫描数据库中的一些实体,并每隔n分钟更新一个过期(“isexpired”)标志。在此之后,我会将整个实体作为json发布到一个url,该url被指定为同一实体的属性 此代码运行批处理作业并更新数据库,但它始终显示以下错误,并且在Springsource STS中调试时,程序似乎在更新数据库之前连续循环多次: INFO: Overriding bean definition for bean 'expireAndPostApiEntityJob': replacing [Generic be

我需要扫描数据库中的一些实体,并每隔n分钟更新一个过期(“isexpired”)标志。在此之后,我会将整个实体作为json发布到一个url,该url被指定为同一实体的属性

此代码运行批处理作业并更新数据库,但它始终显示以下错误,并且在Springsource STS中调试时,程序似乎在更新数据库之前连续循环多次:

INFO: Overriding bean definition for bean 'expireAndPostApiEntityJob': replacing [Generic bean: class [org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] with [Generic bean: class [org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null]
Jan 19, 2015 4:46:56 PM org.springframework.core.io.support.PropertiesLoaderSupport loadProperties
INFO: Loading properties file from class path resource [application.properties]
Jan 19, 2015 4:46:56 PM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO: Overriding bean definition for bean 'itemReader': replacing [Generic bean: class [org.springframework.batch.item.database.JdbcCursorItemReader]; scope=step; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring/batch/jobs/job-extract-users.xml]] with [Root bean: class [org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in BeanDefinition defined in class path resource [spring/batch/jobs/job-extract-users.xml]]
Jan 19, 2015 4:46:56 PM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO: Overriding bean definition for bean 'pagingItemReader': replacing [Generic bean: class [org.springframework.batch.item.database.JdbcPagingItemReader]; scope=step; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring/batch/jobs/job-extract-users.xml]] with [Root bean: class [org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in BeanDefinition defined in class path resource [spring/batch/jobs/job-extract-users.xml]]
Jan 19, 2015 4:46:56 PM org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
INFO: Overriding bean definition for bean 'apiItemProcessor': replacing [Generic bean: class [com.x.apimanagerbatchjob.ApiItemProcessor]; scope=step; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [spring/batch/jobs/job-extract-users.xml]] with [Root bean: class [org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in BeanDefinition defined in class path resource [spring/batch/jobs/job-extract-users.xml]]
Jan 19, 2015 4:46:56 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@7faf889f: defining beans [jobRepository,transactionManager,jobLauncher,databaseProperties,dataSource,itemReader,pagingItemReader,apiItemProcessor,oracleItemWriter,org.springframework.batch.core.scope.internalStepScope,org.springframework.beans.factory.config.CustomEditorConfigurer,org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor,expireAndPostApiEntityStep,expireAndPostApiEntityJob,runScheduler,org.springframework.scheduling.support.ScheduledMethodRunnable#0,org.springframework.scheduling.config.IntervalTask#0,org.springframework.scheduling.config.ScheduledTaskRegistrar#0,apiDAO,scopedTarget.itemReader,scopedTarget.pagingItemReader,scopedTarget.apiItemProcessor]; root of factory hierarchy
Jan 19, 2015 4:46:56 PM org.springframework.batch.core.launch.support.SimpleJobLauncher afterPropertiesSet
INFO: No TaskExecutor has been set, defaulting to synchronous executor.
Jan 19, 2015 4:46:56 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: oracle.jdbc.driver.OracleDriver
Jan 19, 2015 4:46:56 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [FlowJob: [name=expireAndPostApiEntityJob]] launched with the following parameters: [{isexpired=0}]
Jan 19, 2015 4:46:56 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [expireAndPostApiEntityStep]
Jan 19, 2015 4:46:56 PM org.springframework.batch.core.step.AbstractStep execute
SEVERE: Encountered an error executing the step
org.springframework.batch.item.ItemStreamException: Failed to initialize the reader
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:142)
    at org.springframework.batch.item.database.JdbcPagingItemReader.open(JdbcPagingItemReader.java:249)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
    at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    at com.sun.proxy.$Proxy4.open(Unknown Source)
    at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:96)
    at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:306)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:192)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:137)
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:152)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:131)
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:301)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:134)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:49)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:127)
    at com.x.apimanagerbatchjob.scheduler.RunScheduler.run(RunScheduler.java:33)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalStateException: Cannot open an already opened ItemReader, call close first
    at org.springframework.util.Assert.state(Assert.java:385)
    at org.springframework.batch.item.database.AbstractPagingItemReader.doOpen(AbstractPagingItemReader.java:133)
    at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.open(AbstractItemCountingItemStreamItemReader.java:139)
    ... 40 more
我将在这里内联一些上下文配置和spring代码。 App.java-应用程序的入口点。

public class App {

    public static void main(String[] args) {

        String[] springConfig = { "spring/batch/jobs/job-extract-users.xml" };

        @SuppressWarnings({ "resource", "unused" })
        ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
    }

}
RunScheduler.java-启动作业的类

Component
public class RunScheduler {


  public void run() {

      String[] springConfig = { "spring/batch/jobs/job-extract-users.xml" };

        @SuppressWarnings({ "resource" })
        ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);

        JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
        Job job = (Job) context.getBean("expireAndPostApiEntityJob");

        try {

            JobParameters param = new JobParametersBuilder().addString("isexpired", "0").toJobParameters();

            JobExecution execution = jobLauncher.run(job, param);
            System.out.println("Exit Status : " + execution.getStatus());
            System.out.println("Exit Status : " + execution.getAllFailureExceptions());

        } catch (Exception e) {
            e.printStackTrace();

        }

        System.out.println("Done");

  }
}
为JdbcPagingItemReader配置bean的上下文xml

<import resource="classpath:spring/**/context.xml" />
    <import resource="classpath:spring/**/database.xml" />

    <bean id="itemReader"
        class="org.springframework.batch.item.database.JdbcCursorItemReader"
        scope="step">
        <property name="dataSource" ref="dataSource" />
        <property name="sql"
            value="select id, apikey, apitoken, url, isexpired, createddate, modifieddate, posterror from apis where isexpired = #{jobParameters['isexpired']}" />
        <property name="rowMapper">
            <bean class="com.x.apimanagerbatchjob.ApiRowMapper" />
        </property>
    </bean>

    <bean id="pagingItemReader"
        class="org.springframework.batch.item.database.JdbcPagingItemReader"
        scope="step">
        <property name="dataSource" ref="dataSource" />
        <property name="queryProvider">
            <bean
                class="org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean">
                <property name="dataSource" ref="dataSource" />
                <property name="selectClause" value="select id, apikey, apitoken, url, isexpired, createddate, modifieddate, posterror" />
                <property name="fromClause" value="from apis" />
                <property name="whereClause" value="where isexpired=:isexpired" />
                <property name="sortKey" value="id" />
            </bean>
        </property>
        <property name="parameterValues">
            <map>
                <entry key="isexpired" value="#{jobParameters['isexpired']}" />
            </map>
        </property>
        <!-- use property place holder configure -->
        <property name="pageSize" value="${pagingItemReader.pageSize}" />
        <property name="rowMapper">
            <bean class="com.x.apimanagerbatchjob.ApiRowMapper" />
        </property>
    </bean>

    <bean id="apiItemProcessor" class="com.x.apimanagerbatchjob.ApiItemProcessor" scope="step"/>

    <bean id="oracleItemWriter"
        class="org.springframework.batch.item.database.JdbcBatchItemWriter">
        <property name="dataSource" ref="dataSource" />
        <property name="sql">
          <value>
                <![CDATA[        
                    update apis
                    set isexpired = 1,
                    modifieddate = CURRENT_DATE
                    where id = :id 
                ]]>
          </value>
        </property>
        <!-- It will take care matching between object property and sql name parameter -->
        <property name="itemSqlParameterSourceProvider">
            <bean
            class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider" />
        </property>
      </bean>

    <job id="expireAndPostApiEntityJob" xmlns="http://www.springframework.org/schema/batch">
        <step id="expireAndPostApiEntityStep">
            <tasklet>
                <chunk reader="pagingItemReader" processor="apiItemProcessor" writer="oracleItemWriter"
                    commit-interval="1" />
            </tasklet>
        </step>
    </job>

    <bean id="runScheduler" class="com.x.apimanagerbatchjob.scheduler.RunScheduler" />

  <!-- Run every 900 seconds (15 mins) -->
  <task:scheduled-tasks>

    <task:scheduled ref="runScheduler" method="run" fixed-delay="${scheduler.interval}" /> 

    <!-- 
    <task:scheduled ref="runScheduler" method="run" cron="*/900 * * * * *" />
    -->
  </task:scheduled-tasks>

  <bean id="apiDAO" class="com.x.apimanagerbatchjob.ApiDAOJDBCTemplateImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>


我将非常感谢您的帮助。非常感谢。

我认为这个问题是由于您的应用程序中存在一些递归。您的
App
类正在引导与
RunScheduler
类相同的上下文。我建议有两种情况。一个由处理刚刚启动调度程序的
App
类引导,另一个由
RunScheduler
类引导以引导作业的上下文。您甚至可以将通用组件移动到
应用程序
类引导中的组件,并在
运行调度程序
引导其上下文时将其设置为父上下文。

尝试将您的读卡器bean与@StepScope绑定。它为我解决了这个问题

非常感谢Michael。虽然我不确定这是否是问题的原因,但我会尝试你的建议。我之所以这么说,是因为在我第二次添加调度程序并引用上下文之前,我已经得到了这个异常。我知道两次引用同一个上下文可能是一个问题,但是对于spring和SpringBatch来说是新手,我当时不知道如何将它们分开,但我想我现在知道了。考虑到我在引入RunScheduler类之前得到了这个示例,您认为还有什么可能是导致这个问题的原因呢。我找不到一个简单的例子来考虑我的场景,我必须在不同的包中从不同的类访问上下文。我通过将App和Runscheduler类合并在一起并使声明的上下文保持静态来实现它,我认为这是非常错误的。它停止了过度循环,但由于Java.nullpointer异常而暂停。