2015-02-11 12 views
7

Ich habe Standalone Frühjahr Batch-Job. Das funktioniert völlig in Ordnung, wenn sie in JUNITSpring Batch Scope Problem bei der Verwendung von Spring Boot

@RunWith(SpringJUnit4ClassRunner.class) 
//@SpringApplicationConfiguration(classes = KPBootApplication.class) 
@ContextConfiguration(locations={"classpath:kp-sb.xml"}) 
public class KPBootApplicationTests { 

    private final static Logger LOG=LoggerFactory.getLogger(KPBootApplicationTests.class); 

    @Autowired 
    ApplicationContext context; 

    @Autowired 
    private JobLauncher jobLauncher; 

    @Autowired 
    private Job job; 

    @Test 
    public void testJob() { 

     final JobParameters jobParameters = new JobParametersBuilder() 
       .toJobParameters(); 

     JobExecution execution; 
     try { 
      execution = jobLauncher.run(job, jobParameters); 
      final ExitStatus status = execution.getExitStatus(); 

      if (ExitStatus.COMPLETED.getExitCode().equals(status.getExitCode())) { 
       LOG.info("Job completed Yeaaaaaaaa!!!!!"); 
      } else { 
       final List<Throwable> exceptions = execution 
         .getAllFailureExceptions(); 
       for (final Throwable throwable : exceptions) { 
        LOG.error(throwable.getMessage(), throwable); 

       } 
      } 
     } catch (JobExecutionAlreadyRunningException e) { 
      LOG.error(e.getMessage(), e); 
     } catch (JobRestartException e) { 
      LOG.error(e.getMessage(), e); 
     } catch (JobInstanceAlreadyCompleteException e) { 
      LOG.error(e.getMessage(), e); 
     } catch (JobParametersInvalidException e) { 
      LOG.error(e.getMessage(), e); 
     } 

    } 

} 

und die Konfigurationsdatei

<!-- Below code till Job Repo is commented out during spring-boot --> 
<context:property-placeholder 
    properties-ref="kpProps" /> 
<util:properties id="kpProps"> 
    <prop key="app.file.path"> 
     D:/temp/kp1/all 
    </prop> 
    <prop key="app.max_thread_num"> 
     10 
    </prop> 
</util:properties> 

<!-- 
<bean id="jobLauncher" 
    class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> 
    <property name="jobRepository" ref="jobRepository" /> 
</bean> 

<bean id="jobRepository" 
    class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"> 
    <property name="transactionManager" ref="batchTransactionManager" /> 
</bean> 
--> 

<bean id="batchTransactionManager" 
    class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"> 
    <property name="rollbackOnCommitFailure" value="false" /> 
</bean> 

<bean id="multiResourcePartitionerReq" 
    class="org.springframework.batch.core.partition.support.MultiResourcePartitioner"> 
    <property name="resources" value="file:${app.file.path}/kp_http_request*" /> 
</bean> 

<bean id="multiResourcePartitionerRes" 
    class="org.springframework.batch.core.partition.support.MultiResourcePartitioner"> 
    <property name="resources" value="file:${app.file.path}/kp_http_response*" /> 
</bean> 

<bean id="kpPool" 
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor" 
    destroy-method="destroy"> 
    <property name="maxPoolSize" value="${app.max_thread_num}" /> 
</bean> 

<bean id="idIncrementer1" 
    class="org.springframework.batch.core.launch.support.RunIdIncrementer" /> 

<batch:job id="kpGenJob" incrementer="idIncrementer1" 
    job-repository="jobRepository"> 
    <batch:split id="splitStep" next="step4"> 
     <batch:flow> 
      <batch:step id="step2"> 
       <batch:partition partitioner="multiResourcePartitionerReq" 
        step="step2.slave"> 
        <batch:handler task-executor="kpPool" /> 
       </batch:partition> 
      </batch:step> 
     </batch:flow> 
     <batch:flow> 
      <batch:step id="step3"> 
       <batch:partition partitioner="multiResourcePartitionerRes" 
        step="step3.slave"> 
        <batch:handler task-executor="kpPool" /> 
       </batch:partition> 
      </batch:step> 
     </batch:flow> 
    </batch:split> 
    <batch:step id="step4"> 
     <batch:tasklet transaction-manager="batchTransactionManager"> 
      <ref bean="kptasklet" /> 
     </batch:tasklet> 
    </batch:step> 
</batch:job> 

<batch:step id="step2.slave"> 
    <batch:tasklet transaction-manager="batchTransactionManager"> 
     <batch:chunk reader="reqItemReader" writer="cvsFileItemWriter" 
      commit-interval="10000" /> 
    </batch:tasklet> 
</batch:step> 

<batch:step id="step3.slave"> 
    <batch:tasklet transaction-manager="batchTransactionManager"> 
     <batch:chunk reader="resItemReader" writer="cvsFileItemWriter" 
      commit-interval="10000" /> 
    </batch:tasklet> 
</batch:step> 

<bean id="reqItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" 
    scope="step"> 

    <property name="resource" value="#{stepExecutionContext['fileName']}" /> 

    <property name="lineMapper"> 
     <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"> 
      <!-- split it --> 
      <property name="lineTokenizer"> 
       <bean 
        class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"> 
        <property name="includedFields" value="5,6,8,10,11"></property> 
        <property name="names" 
         value="f1,f2,f3,f4,f5" /> 
        <property name="strict" value="false" /> 
       </bean> 
      </property> 
      <property name="fieldSetMapper"> 
       <bean 
        class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"> 
        <property name="prototypeBeanName" value="tblHttpData" /> 
       </bean> 
      </property> 
     </bean> 
    </property> 
    <property name="linesToSkip" value="1"></property> 
</bean> 

<bean id="tblHttpData" class="com.kp.batch.batch.job.domain.TblHttpData" 
    scope="prototype" /> 

<bean id="resItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" 
    scope="step"> 

    <property name="resource" value="#{stepExecutionContext['fileName']}" /> 

    <property name="lineMapper"> 
     <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"> 
      <!-- split it --> 
      <property name="lineTokenizer"> 
       <bean 
        class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"> 
        <property name="includedFields" value="3,4"></property> 
        <property name="names" value="f1,f2" /> 
        <property name="strict" value="false" /> 
       </bean> 
      </property> 
      <property name="fieldSetMapper"> 

       <bean 
        class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper"> 
        <property name="prototypeBeanName" value="tblHttpData" /> 
        <property name="strict" value="true" /> 
       </bean> 
      </property> 
     </bean> 
    </property> 
    <property name="linesToSkip" value="1"></property> 
</bean> 

<bean id="kptasklet" class="com.kp.batch.batch.job.step.KPTasklet" /> 

<bean id="cvsFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" 
    scope="step"> 
    <!-- write to this csv file --> 
    <property name="resource" value="#{stepExecutionContext['fileName']}.tmp" /> 
    <property name="shouldDeleteIfExists" value="true" /> 

    <property name="lineAggregator"> 
     <bean 
      class="org.springframework.batch.item.file.transform.DelimitedLineAggregator"> 
      <property name="delimiter" value="," /> 

      <property name="fieldExtractor"> 
       <bean 
        class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor"> 
        <property name="names" 
         value="server,refferer,application,baseApplication,httpSize" /> 
       </bean> 
      </property> 
     </bean> 
    </property> 

</bean> 

Die Hauptklasse

@SpringBootApplication 
@EnableBatchProcessing 
@ImportResource(value={"classpath:spring-context.xml"}) 
public class KPBootApplication { 

    private final static Logger LOG = LoggerFactory 
      .getLogger(KPBootApplication.class); 

    public static void main(String[] args) { 
     ApplicationContext ctx = SpringApplication.run(
       KPBootApplication.class, args); 
     LOG.info("Application KPBOOT Started"); 
     SayHello hello = (SayHello) ctx.getBean("sayHello"); 
     if (hello != null) { 
      LOG.debug("hello is not null"); 
      LOG.info("Got message {}", hello.getMessage()); 
     } else { 
      LOG.debug("hello is null"); 
     } 
     LOG.info("Done"); 

    } 
} 

Wenn ich contextconfiguration Anmerkung Kommentar und Feder-boot ermöglichen durch Aktivieren @SpringApplicationConfiguration (Hinweis: Ich habe den Spring-Batch mithilfe der Annotation @EnableBatchProcessing aktiviert und Beans auskommentieren das ist automcatically durch feder Boot für das Frühjahr Batch wie JobRepo erstellt bekomme ich folgende Fehlermeldung, dass kein Zusammenhang Halter für Schritt Umfang

java.lang.IllegalStateException: Failed to load ApplicationContext 
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:94) 
    at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:72) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117) 
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) 
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:212) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:200) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:252) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:254) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:217) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'step2': Cannot resolve reference to bean 'step2.slave' while setting bean property 'step'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'step2.slave': Cannot resolve reference to bean 'reqItemReader' while setting bean property 'itemReader'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reqItemReader': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1469) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:743) 
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480) 
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691) 
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321) 
    at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:98) 
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:68) 
    at org.springframework.test.context.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:86) 
    ... 25 common frames omitted 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'step2.slave': Cannot resolve reference to bean 'reqItemReader' while setting bean property 'itemReader'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reqItemReader': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1469) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476) 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303) 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) 
    ... 42 common frames omitted 
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reqItemReader': Scope 'step' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for step scope 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:352) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194) 
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351) 
    ... 52 common frames omitted 
Caused by: java.lang.IllegalStateException: No context holder available for step scope 
    at org.springframework.batch.core.scope.StepScope.getContext(StepScope.java:160) 
    at org.springframework.batch.core.scope.StepScope.get(StepScope.java:99) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) 
    ... 54 common frames omitted 

nicht sicher, warum Frühjahr Boot-Fehler wirft
HINWEIS: Feder-Boot-Version 1.2 .1

+0

Was ist in Ihrer 'KPBootApplication.class'? –

+0

@DaveSyer ist die Hauptklasse –

Antwort

10

Dies kann ein Fehler sein (wir untersuchen noch), aber wir haben eine Arbeit herum. Der Grund dafür ist, dass bei der Verwendung von @EnableBatchProcessing die StepScope, die automatisch konfiguriert wird, java config annimmt und daher die Step-scoped-Beans nicht proxyt, was dazu führt, dass sie zu früh erstellt werden. Die Arbeit um ist, um manuell ein StepScope in der XML-Konfiguration mit der folgenden Konfiguration zu konfigurieren:

<bean id="stepScope" class="org.springframework.batch.core.scope.StepScope"> 
    <property name="autoProxy" value="true"/> 
</bean> 
+0

Das hat perfekt funktioniert ... vielen Dank .... Muss ich JIRA erstellen? –

+2

Haben Sie bereits: https://jira.spring.io/browse/BATCH-2351 –

+2

Eine weitere wichtige Bemerkung über das Hinzufügen der Step/JobScope-Bean-Definition über JavaConfig: Sie muss in einer separaten @Configuration-Klasse deklariert werden Importieren), oder es treten Zyklusprobleme auf. – kij

3

Michaels Kommentar ist für mich arbeiten, ich bin auch JavaConfig copy-paste Alternative für faule Leute wie ich, die Bereitstellung :)

+0

Wie haben Sie es geschafft, StepScope zu instanziieren? – CKing

+0

Dieser Code erstellt tatsächlich Instanz von StepScope. Sie müssen diesen Code in jede @Configuration-Klasse einfügen. – Gondy

+0

Das Problem hier ist, dass es zwei "StepScope" -Typen in der "Spring" -Distribution gibt. Das eine ist eine Anmerkung und das andere ist eine Klasse. Ich hatte angenommen, dass Sie die StepScope-Annotation und damit die Verwirrung instanziieren würden. – CKing

1

Wenn Sie @RunWith(SpringRunner.class) verwenden, wird die Festlegung von @TestExecutionListeners({..., StepScopeTestExecutionListener.class}) über Ihrer Klasse die Bereiche für Sie einrichten.

Gleiches mit @TestExecutionListeners({..., JobScopeTestExecutionListener.class}) für JobScope.

Verwandte Themen