Description of problem:
In testing, I realized that I had a globally scoped bean "partitionHandler" of type o.s.b.i.p.MessageChannelPartitionHandler that needed to be step scoped.
When I followed the examples of the other step scoped beans in the xml file, the job failed to load because no step scoped bean was active.
I can make my code as functional as it has been again by removing the scope="step" from the bean definition, but that is not a step forward and does not help me to understand the underlying issue to move forward.
Is there a functional example of making a MessageChannelPartitionHandler a step scoped bean in an xml context?
(Edit 2)
The root issue appears to be that the aggregator is defined as a global bean, but all of the beans it references (am-partitionHandler
, am-replyChannel
, and am-aggregatedReplyChannel
) are step scoped beans.
<int:aggregator ref="am-partitionHandler"
input-channel="am-replyChannel"
output-channel="am-aggregatedReplyChannel"/>
(Edit )
In tracing the code:
- ResourceXmlApplicationContext.preInstantiateSingletons() is looking for an o.s.i.c.AggregatorFactoryBean that is expected to be a singleton, then attempting to create it in the step scope as a ReleaseStrategyFactoryBean.
- AbstractBeanFctory.doGetBean() is looking for a bean with the name "scopedTarget.partitionHandler" in the scope named "step", then throwing the exception.
- StepScope.getContext() is not finding the stepScope in StepSynchronizationManager.getContext(), throwing the root exception
When chasing other links:
One of those I found is an almost identical symtom in a previous SE question of mine: Spring Batch - why is the job Step bean is being created/executed in the web context instead of the Job context? . The original link describes issues loading one of my application at job execution time, while this happens to a spring batch integration class during the initial XML context loading time (at application startup), well before the bean is actually executed.
XML snip:
<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>
Log snip:
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]