为什么这个 Spring Batch Bean 没有自动连接到 Grails 中?

Why is this Spring Batch Bean not auto wired in Grails?

我不确定为什么我的 delegate bean 没有被连接并且为空。请问有人可以给点建议吗?

在ScheduleJobBatchConfig.groovy内:

beans {
    xmlns batch:"http://www.springframework.org/schema/batch"

    batch.job(id: 'scheduleJob', restartable: true) {
        batch.step(id: 'scheduleStep1') {
            batch.tasklet {
                batch.chunk(
                        reader: 'scheduleReaderWrapper',
                        writer: 'scheduleWriter',
                        'commit-interval': 50
                )
            }
        }
    }

    scheduleReaderWrapper(ScheduleReaderWrapper) { bean ->
        bean.autowire = 'byName'
        delegate = ref('basicScheduleReader')  // this is null
    }

    basicScheduleReader(FlatFileItemReader) { bean ->
        bean.scope = 'step'
        resource = "#{jobParameters['file']}"
        lineMapper = ref('scheduleLineMapper')
    }

    // more sub-beans here
}

这是未连接的 bean(在 src/groovy 内):

public class ScheduleReaderWrapper implements ItemStreamReader<Object> {

    private ItemStreamReader<Object> delegate;

    public Object read() throws Exception {
        // do some reading here
        return schedule;
    }

    public void setDelegate(ItemStreamReader<Object> delegate) {
        this.delegate = delegate;
    }

    public void close() throws ItemStreamException {
        delegate.close();
    }

    public void open(ExecutionContext arg0) throws ItemStreamException {
        delegate.open(arg0);
    }

    public void update(ExecutionContext arg0) throws ItemStreamException {
        delegate.update(arg0);
    }
}

所有闭包都有一个可设置的 delegate 属性 通过 setDelegategetDelegate 方法。这在实现 DSL 时经常使用。

此代码作为注册 bean 定义的方法调用被调用:

scheduleReaderWrapper(ScheduleReaderWrapper) { bean ->
    bean.autowire = 'byName'
    delegate = ref('basicScheduleReader')
}

它与 void beanName(Class c, Closure c) { ... } 基本相同,它使用 Groovy 中的能力将闭包留在方法参数之外。显然没有 scheduleReaderWrapper 方法,但是 DSL 委托(bean 构建器)处理丢失的方法异常并使用方法名称作为 bean 名称,并且由于第一个 arg 是 Class 它用作bean class,可选的第二个 arg 是闭包,因此调用它来自定义 bean 属性。

bean 构建器依赖于调用不存在的方法以及获取和设置不存在的属性,因此它会收到这些调用的通知并且可以使用 method/property 名称和参数来配置 bean。

这个

delegate = ref('basicScheduleReader')

相当于

setDelegate(ref('basicScheduleReader'))

但它是在一个闭包内调用的,闭包有一个 setDelegate 方法。如果它使用闭包 class 中不存在的任何其他 属性 名称,它将触发丢失的 属性 异常,并被解释为设置 属性 的调用在 ScheduleReaderWrapper 实例上,同时由 Spring.

配置

例如,如果您将 ScheduleReaderWrapper 中的 属性 更改为 wrappedReader,它将按预期工作:

wrappedReader = ref('basicScheduleReader')