Внутри моего веб-приложения я запускаю и управляю несколькими десятками подпружиненных процессов для длительных операций.
Мне кажется, что Spring-Batch построил задание в контексте веб-приложения, а не в контексте задания, что приводит к неинформативной ошибке "Нет области действия для имени области действия" step "".
Есть идеи, что мне не хватает?
- Версия Java: 1.8
- Версия Spring: 5.1.3.RELEASE
- Версия с подпружиненной версией: 4.1.1.RELEASE
- Версия Tomcat: 8.0
Изменения / обновления, сделанные после публикации вопроса:
- Реализован реестр заданий для инкапсуляции заданийи обновил запуск задания для использования реестра заданий - без изменений
- Оба режима TARGET_CLASS и DEFAULT proxy были опробованы и работают одинаково - без изменений
- Added ""к объявлению бина StepScope в ответ Махмуда Бена Хассина - без изменений
Журнал ...
taskExecutor-1 2019-02-12 13:31:32,836 ERROR o.s.b.c.s.AbstractStep - Encountered an error executing step step0002-init-prepareGraphDatastore in job hierarchy-analyser
java.lang.IllegalStateException: No Scope registered for scope name 'step'
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:350) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) ~[spring-aop-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:672) ~[spring-aop-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at com.xxxx.MyExampleReader$$EnhancerBySpringCGLIB$$b0c58048.beforeStep(<generated>) ~[relationship-analyzer-tool-BASELINE.jar:na]
at org.springframework.batch.core.listener.CompositeStepExecutionListener.beforeStep(CompositeStepExecutionListener.java:77) ~[spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:199) ~[spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:136) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:313) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:144) [spring-batch-core-4.1.1.RELEASE.jar:4.1.1.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_162]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_162]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_162]
Spring-batch job XML ...
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="false"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd">
<description>Hierarchy Analyzer</description>
<context:component-scan
base-package="com.xxxx.*" />
<bean class="org.springframework.batch.core.scope.JobScope" />
<bean class="org.springframework.batch.core.scope.StepScope" />
<batch:job id="hierarchy-analyser">
<batch:listeners>
<batch:listener
ref="someJobListeners" />
</batch:listeners>
<batch:step id="step0002-init-long-running-process"
allow-start-if-complete="true">
<batch:tasklet
transaction-manager="jtaTransactionManager" start-limit="100">
<batch:chunk reader="myExampleReader"
writer="myExampleWriter" commit-interval="1" />
</batch:tasklet>
<batch:fail on="FAILED" />
<batch:next on="*"
to="step0002-1-more-stuff" />
<batch:listeners>
<batch:listener ref="myExampleReader" />
<batch:listener ref="myExampleWriter" />
</batch:listeners>
</batch:step>
</batch:job>
</beans>
MyExampleReader ...
@Component
@Scope(value = "step", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyExampleReader
implements ItemReader<TableMetadata>,
StepExecutionListener { ... }
Код, который запускает задание ...
private ResultWrapper<Job> setupJobById(Resource r) throws Exception {
ResultWrapper<Job> result = new ResultWrapper<Job>();
try {
Resource[] res = new Resource[] { r };
ClasspathXmlApplicationContextsFactoryBean b = new ClasspathXmlApplicationContextsFactoryBean();
b.setApplicationContext(applicationContext);
b.setResources(res);
ApplicationContextJobFactory factory = new ApplicationContextJobFactory(
r.getFilename().substring(0, r.getFilename().lastIndexOf('.')), b.getObject()[0]);
result.succeed(factory.createJob());
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
result.fail(null, ex.getMessage(), ex);
}
return result;
}
Внутри AbstractBeanFactory.doGetbean (), это содержимое контекста пружины:
{request=org.springframework.web.context.request.RequestScope@3e707e1c, session=org.springframework.web.context.request.SessionScope@375463f}
Обновление: пояснения к ответу
Был ряд проблем с кодом, которые способствовали этому.
Класс, который я искал, отсутствовал ни в одном из путей сканирования контекста в задании, но он был в пути глобального сканирования контекста. Санитарная обработка кода для открытых форумов скрывала это от любых респондентов.
Исходный код не следовал согласованной практике для прокси-режимов во всем приложении. Не было никаких причин не следовать согласованным рекомендациям во всем.
Неправильное использование внутреннего реестра реестра привелок общей "странности".
Что касается вопроса «почему» в исходном вопросе, ответ заключается в том, что Spring оценивает область действия во время сканирования контекста для каждого контекста.Если bean-компонент не загружен с контекстом задания (скажем, из-за того, что в файле job.xml отсутствует один из требуемых путей к классам), то при отложенной загрузке Spring пытается загрузить bean-компонент и находит его в родительском classpath, который оказываетсятот, отсканированный веб-конфигурации.Боб объявлен "Шагом".У webconfig, конечно, нет области действия шага.
Сообщение об ошибке является правильным (английский: чувак, этот компонент объявлен как область действия шага, но его нет в контексте), и вводит в заблуждение (я вижув задании, что есть область действия шага, она выполняется в области действия шага, другие компоненты работают в области действия шага, WTH ??? !!!!!).
Я хотел бы видеть более интеллектуальногосообщения об ошибках возвращены из Spring.Легко терять дни, гоняясь за сообщениями об ошибках, которые абсолютно точны, но скрывают истинный источник проблемы.