2016-02-20 90 views
0

我正在使用spring批处理为了从数据库中读取数据(使用分区)并将其写入基于输入键 - 1,2,3,4的一组文件。Spring批处理问题w/CompositeItemWriter和ClassifierCompositeItemWriter

我已经创建了一个CompositeItemWriter,它是两个ClassifierCompositeItemWriter(s)的组合。尽管我已经注册了独立作家流,我仍然得到以下异常:

org.springframework.batch.item.WriterNotOpenException: Writer must be open before it can be written to 

我甚至尝试注册ItemWriter1和ItemWriter2如流,但是,这给了我一个不同的错误:

Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy13 implementing org.springframework.batch.item.ItemWriter,java.io.Serializable,org.springframework.aop.scope.ScopedObject,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.ItemStream] for property 'streams[0]': no matching editors or conversion strategy found 
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:264) 
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:128) 
    at org.springframework.beans.TypeConverterDelegate.convertToTypedArray(TypeConverterDelegate.java:463) 
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:195) 
    at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:448) 
    ... 74 more 

我甚至在编写器中实现了ItemStream,但它还没有工作。

public class WriterA1 implements ItemWriter<List<Object>>, ItemStream { 
... 
} 

下面是XML配置:

...

<job id="abcJob" xmlns="http://www.springframework.org/schema/batch" 
    restartable="true"> 

    <step id="masterStep"> 
     <partition step="slaveStep" partitioner="abcPartitioner"> 
      <handler grid-size="${grid-size}" task-executor="abcTaskExecutor" /> 
     </partition>    
    </step> 

</job> 

<step id="slaveStep" xmlns="http://www.springframework.org/schema/batch"> 
     <tasklet transaction-manager="transactionManager"> 
      <chunk reader="abcReader" writer="abcWriter" 
       processor="abcProcessor" commit-interval="${a}" skip-limit="${b}" retry-limit="${c}" > 

       <streams> 
        <!-- 
        <stream ref="ItemWriter1"/> 
        <stream ref="ItemWriter2"/> 
        -->       
        <stream ref="WriterA1"/> 
        <stream ref="WriterB2"/> 
        <stream ref="WriterC3"/> 
        <stream ref="WriterD4"/>            
        <stream ref="WriterA5"/> 
        <stream ref="WriterB6"/> 
        <stream ref="WriterC7"/> 
        <stream ref="WriterD8"/> 

       </streams>     

      </chunk> 
      <listeners> 
       ...          
      </listeners>             
     </tasklet>    
    </step> 


<bean id="abcWriter" class="org.springframework.batch.item.support.CompositeItemWriter" scope="step"> 
    <property name="delegates"> 
     <list>    
      <ref bean="ItemWriter1" /> 
      <ref bean="ItemWriter2" /> 
     </list> 
    </property> 
</bean> 

<bean id="ItemWriter1" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter" scope="step"> 
    <property name="classifier"> 
     <bean 
      class="org.springframework.classify.BackToBackPatternClassifier"> 
      <property name="routerDelegate"> 
       <bean class="xxx.xxx.xxx.xxx.Classifier1" scope="step"/> 
      </property> 
      <property name="matcherMap"> 
       <map> 
        <entry key="1" value-ref="WriterA1" /> 
        <entry key="2" value-ref="WriterB2" /> 
        <entry key="3" value-ref="WriterC3" /> 
        <entry key="4" value-ref="WriterD4" /> 
       </map> 
      </property> 
     </bean>  
    </property> 
</bean> 

<bean id="ItemWriter2" class="org.springframework.batch.item.support.ClassifierCompositeItemWriter" scope="step"> 
    <property name="classifier"> 
     <bean 
      class="org.springframework.classify.BackToBackPatternClassifier"> 
      <property name="routerDelegate"> 
       <bean class="xxx.xxx.xxx.xxx.Classifier2" scope="step"/> 
      </property> 
      <property name="matcherMap"> 
       <map> 
        <entry key="1" value-ref="WriterA5" /> 
        <entry key="2" value-ref="WriterB6" /> 
        <entry key="3" value-ref="WriterC7" /> 
        <entry key="4" value-ref="WriterD8" /> 
       </map> 
      </property> 
     </bean>  
    </property> 
</bean> 

<bean id="WriterA1" class="xxx.xxx.xxx.xxx.WriterA1" scope="step"> 

</bean> 
<bean id="WriterB2" class="xxx.xxx.xxx.xxx.WriterB2" scope="step"> 

</bean> 
<bean id="WriterC3" class="xxx.xxx.xxx.xxx.WriterC3" scope="step"> 

</bean> 
<bean id="WriterD4" class="xxx.xxx.xxx.xxx.WriterD4" scope="step"> 

</bean> 
    <bean id="WriterA5" class="xxx.xxx.xxx.xxx.WriterA5" scope="step"> 

    </bean> 
    <bean id="WriterB6" class="xxx.xxx.xxx.xxx.WriterB6" scope="step"> 

    </bean> 
<bean id="WriterC7" class="xxx.xxx.xxx.xxx.WriterC7" scope="step"> 

</bean> 
<bean id="WriterD8" class="xxx.xxx.xxx.xxx.WriterD8" scope="step"> 

</bean> 

请指教。

+0

哪个类(甚至更好,哪个bean)抛出'org.springframework.batch.item.WriterNotOpenException'? – Artefacto

+0

WriterA1( )正在抛出异常。我的理解是,任何正在根据输入键调用的作者都将抛出相同的异常。 – ridsoc

+0

除上述注释外:项目编写者在重写的“写入”方法中使用BeanIOFlatFileItemWriter。最初,我已经通过xml配置将编写器配置为使用BeanIOFlatFileItemWriter,但是,它无法检测到文件必须被创建的驱动器,该文件声明“本来不应该发生的访问被拒绝”,因为我在本地拥有管理员权限机。因此,我不得不求助于写作个人作品。 – ridsoc

回答

0

你有三种类型的作家。从上至下:

  • abcWriterCompositeItemWriter。它通过将ItemStream方法调用委托给代表(此处为ItemWriter1ItemWriter2)实施ItemStream,前提是他们实施了ItemStream。事实并非如此。但即使他们实施了ItemStream,您也不应该在步骤配置中单独将ItemWriter1ItemWriter2注册为流(在下一个项目符号中有另一个独立原因)。

  • ItemWriter1/ItemWriter2ClassifierCompositeItemWriter s。这个类没有实现ItemStream,所以你一定不要在步骤配置中将它们注册为流。

  • WriterA1属于BeanIOFlatFileItemWriter类型,因此实施ItemStream。因为包装它们的ClassifierCompositeItemWriter不称为它们的ItemStream方法(与CompositeItemWriter不同),所以必须将中的每一个都注册为步骤配置中的流。

但是,这是你声称你有。然而,您的作用域范围内的bean正在通过不实现ItemStreamItemStreamWriter(而不是ItemWriter)的单例bean进行代理(使用接口代理模式)。确保您在<bean>元素内部执行的类具有实施ItemStream。您也可以尝试明确创建范围代理bean(使用ScopedProxyFactoryBean并设置interfaces属性)。或者你可以尝试在ScopedProxyFactoryBean::setBeanFactory中打破一个断点,当targetBeanName包含字符串WriterXX(它将类似于stepScopedTarget.WriterD8)并试图理解为什么ItemStream接口未被代理。

+0

我相信这就是我在下面做的。它仍然不起作用。 \t \t <流REF = “WriterA1”/> \t <流REF = “WriterB2”/> \t <流REF = “WriterC3”/> \t <流REF = “WriterD4”/> \t <流REF = “WriterA5”/> \t <流REF = “WriterB6”/> \t <流REF = “WriterC7”/> \t <流REF = “WriterD8”/> 我做得错这里? – ridsoc

+0

@ridsoc我加了一些提示。 – Artefacto

+0

问题出在实现ItemStream接口的同时覆盖open(ExecutionContext executionContext)方法,其中我必须设置BeanIOFlatFileItemWriter细节并在writer实例上调用open方法。我现在可以将数据写入一个单独的文件,该文件被设置为作者的资源。但是,我的目标是根据输入密钥将数据写入文件。例如,如果我的输入密钥= 1,我想创建一个文件为File_1并将数据写入该文件。我无法做到这一点。请指教。 – ridsoc