问题描述:
在测试中,我意识到我有一个全局作用域的bean“partitionHandler”,类型为o.s.b.I.p.MessageChannelPartitionHandler,需要对其进行步骤作用域处理。
当我按照xml文件中其他步骤作用域bean的示例进行操作时,由于没有任何步骤作用域的bean处于活动状态,因此无法加载作业。
通过从bean定义中删除scope=“step”,我可以使我的代码再次发挥作用,但这并不是向前迈出的一步,也无助于我理解前进的根本问题。
是否有将MessageChannelPartitionHandler作为xml上下文中步骤范围的bean的功能示例?
(编辑2)
根本问题似乎是聚合器被定义为全局bean,但它引用的所有bean(
am-partitionHandler
,
am-replyChannel
和
am-aggregatedReplyChannel
)是步骤范围的bean。
<int:aggregator ref="am-partitionHandler"
input-channel="am-replyChannel"
output-channel="am-aggregatedReplyChannel"/>
(编辑)
在跟踪代码时:
-
ResourceXmlApplicationContext.preInstantiateSingletonss()正在寻找一个o.s.i.c.AggregatorFactoryBean,它应该是一个单例,然后试图在步骤范围中将其创建为ReleaseStrategyFactoryBean。
-
AbstractBeanFactory.doGetBean()正在名为“step”的作用域中查找名称为“scopedTarget.partitionHandler”的bean,然后引发异常。
-
在StepSynchronizationManager.getContext()中找不到StepScope,引发根异常
-
追逐其他链接时:
我在之前的一个SE问题中发现了一个几乎相同的符号:
Spring Batch - why is the job Step bean is being created/executed in the web context instead of the Job context?
。原始链接描述了在作业执行时加载一个应用程序的问题,而在初始XML上下文加载时(在应用程序启动时),早在bean实际执行之前,spring批处理集成类就会出现这种情况。
XML片段:
<bean class="org.springframework.batch.core.scope.JobScope">
<property name="proxyTargetClass" value="true" />
</bean>
<bean class="org.springframework.batch.core.scope.StepScope">
<property name="proxyTargetClass" value="true" />
</bean>
<bean id="retryListItemWriterListener"
name="retryListItemWriterListener"
class="com.myApp.jobscope.RetryListItemWriterListener"
scope="step" /> <!-- no problems with this and other step scoped beans -->
<int:channel id="aggregatedReplyChannel" scope="step">
<int:queue/>
</int:channel>
<bean id="partitionHandler"
name="partitionHandler"
class="org.springframework.batch.integration.partition.MessageChannelPartitionHandler"
scope="step"> <!-- step scope breaks this bean at initialization -->
<property name="stepName" value="as-step0002.slave"/>
<property name="gridSize" value="3"/>
<property name="replyChannel" ref="aggregatedReplyChannel"/>
<property name="jobExplorer" ref="jobExplorer"/>
<property name="releaseStrategy" ref="releaseStrategy" />
<property name="messagingOperations">
<bean class="org.springframework.integration.core.MessagingTemplate">
<property name="defaultChannel" ref="requestsChannel"/>
<property name="receiveTimeout" value="1000000"/>
</bean>
</property>
</bean>
<batch:job id="eventuallyconsistent-master">
<batch:step id="am-step0002.master">
<batch:partition partitioner="flatSourceDataPartitioner" handler="partitionHandler"/>
<batch:fail on="FAILED" />
<batch:next on="*" to="am-step9998" />
<batch:listeners>
<batch:listener ref="flatSourceDataPartitioner" />
<batch:listener ref="ruleFactory" />
</batch:listeners>
</batch:step>
</batch:job>
日志剪切:
main 2023-06-29 10:48:54,050 INFO o.s.a.f.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.integration.context.IntegrationObjectSupport.afterPropertiesSet()] because it is marked as final: Consider using interface-based JDK proxies instead!
main 2023-06-29 10:48:54,051 INFO o.s.a.f.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.integration.context.IntegrationObjectSupport.setBeanName(java.lang.String)] because it is marked as final: Consider using interface-based JDK proxies instead!
main 2023-06-29 10:48:54,064 INFO o.s.a.f.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.integration.context.IntegrationObjectSupport.afterPropertiesSet()] because it is marked as final: Consider using interface-based JDK proxies instead!
main 2023-06-29 10:48:54,065 INFO o.s.a.f.CglibAopProxy - Unable to proxy interface-implementing method [public final void org.springframework.integration.context.IntegrationObjectSupport.setBeanName(java.lang.String)] because it is marked as final: Consider using interface-based JDK proxies instead!
main 2023-06-28 17:08:01,054 ERROR c.m.m.AppInitializer - Failed to start bean 'automaticJobRegistrar'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.config.AggregatorFactoryBean#0' defined in file [C:\myApp\jobrepository\eventuallyconsistent-master.xml]: Cannot create inner bean '(inner bean)#5791a9cb' of type [org.springframework.integration.config.ReleaseStrategyFactoryBean] while setting bean property 'releaseStrategy'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5791a9cb': Invocation of init method failed; nested exception is org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.partitionHandler': 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
org.springframework.context.ApplicationContextException: Failed to start bean 'automaticJobRegistrar'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.config.AggregatorFactoryBean#0' defined in file [C:\jobrepository\eventuallyconsistent-master.xml]: Cannot create inner bean '(inner bean)#5791a9cb' of type [org.springframework.integration.config.ReleaseStrategyFactoryBean] while setting bean property 'releaseStrategy'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#5791a9cb': Invocation of init method failed; nested exception is org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.partitionHandler': 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.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.18.jar:5.3.18]
at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.18.jar:5.3.18]
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.18.jar:5.3.18]
at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.18.jar:5.3.18]
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.18.jar:5.3.18]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.18.jar:5.3.18]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.18.jar:5.3.18]