2015-01-19 2 views
1

데이터베이스의 일부 엔티티를 검색하고 만료 시간 ("isexpired") 플래그를 업데이트해야합니다. 이 후 나는 동일한 엔티티의 속성으로 지정된 URL에 json으로 전체 엔티티를 게시합니다.스프링 배치 JdbcPagingItemReader가 제대로 닫히지 않았기 때문에 제대로 초기화되지 않음

이 코드는 배치 작업을 실행하고 데이터베이스를 업데이트하지만 아래의 오류를 보여주는 유지하고 스프링 소스 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.s[email protected]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 

컨텍스트 구성의 일부와 스프링 코드를 여기에 인라인 할 것입니다. 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"); 

    } 
} 

<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> 

내가 도움을 주셔서 감사합니다 JdbcPagingItemReader의 콩을 구성 컨텍스트 XML을 시작 클래스 이걸로. 고맙습니다.

답변

0

제 생각에는이 문제는 앱에서 반복되는 재귀가 있기 때문에 발생한다고 생각합니다. App 클래스는 RunScheduler 클래스와 동일한 컨텍스트를 부트 스트랩합니다. 나는 두 가지 맥락을 갖는 것이 좋습니다. 하나는 스케쥴러 시작을 처리하는 App 클래스에 의해 부트 스트랩되고 다른 하나는 RunScheduler 클래스에 의해 부트 스트랩되어 다른 작업을 부트 스트랩합니다. 공통 컴포넌트를 App 클래스 부트 스트랩으로 이동하여 RunScheduler이 컨텍스트를 부트 스트랩 할 때 상위 컨텍스트로 설정할 수도 있습니다.

+0

고마워요 마이클. 이 문제의 원인인지 확실하지 않지만 귀하의 제안을 시도 할 것입니다. 왜 내가 이렇게 말한 이유는 스케줄러를 추가하고 두 번째로 컨텍스트를 참조하기 전에 이미이 예외가 발생했기 때문입니다. 동일한 문맥을 두 번 언급하는 것이 문제가 될 수 있지만 봄과 봄의 배치에 익숙하지 않다는 것을 알았지 만, 당시와 같이 분리하는 방법을 알지 못했지만 지금 생각합니다. RunScheduler 클래스를 소개하기 전에이 예외를 얻었 음을 고려할 때,이 문제의 원인이 될 수있는 다른 사항은 무엇입니까? – sage

+0

Hello Michael, 코드 예제를 게시 할 수 있습니까? 별도의 패키지에있는 다른 클래스의 컨텍스트에 액세스해야하는 시나리오를 고려한 간단한 예제를 찾을 수 없습니다. App과 Runscheduler 클래스를 병합하고 선언 컨텍스트를 정적으로 만드는 것으로 접근하여 매우 잘못되었다고 생각합니다. 그것은 과도한 루핑을 중지했지만 Java.nullpointer 예외로 인해 실속합니다. – sage

1

독자 콩을 @ StepScope으로 묶어보십시오. 그것은 나를 위해 문제를 해결

관련 문제