Appearance
Spring Batch 重用现有服务教程:ItemReaderAdapter 与 ItemWriterAdapter
🎯 概述:为什么需要重用服务?
在真实业务场景中,Spring Batch 通常需要与其他应用(如在线系统、集成服务或客户端应用)协同工作。常见需求是复用已有的服务组件(如DAO层),避免重复造轮子。Spring Batch 提供了两种优雅的适配器来解决这个问题:
🔧 适配器工作原理
Spring Batch 使用委托模式实现服务复用:
ItemReaderAdapter
:将普通服务方法适配为 ItemReaderItemWriterAdapter
:将普通服务方法适配为 ItemWriter
TIP
适配器就像万能转换器,让普通服务方法无缝接入批处理流程
📖 ItemReaderAdapter 使用指南
核心配置(Kotlin DSL)
kotlin
@Configuration
class BatchConfig {
// 配置ItemReader适配器
@Bean
fun itemReader(): ItemReaderAdapter<Foo> {
return ItemReaderAdapter<Foo>().apply {
targetObject = fooService() // [!code highlight] // 绑定目标服务
targetMethod = "generateFoo" // [!code highlight] // 指定服务方法
}
}
// 被复用的服务
@Bean
fun fooService() = FooService()
}
// 示例服务类
class FooService {
private var count = 0
fun generateFoo(): Foo? {
return if (count < 5) {
count++
Foo("Item-$count")
} else null // [!code warning] // 关键点:必须返回null表示结束
}
}
// 数据对象
data class Foo(val name: String)
关键注意事项
必须遵守的契约
被适配的方法返回值类型必须与 read()
方法相同:
- 正常数据:返回对象实例
- 数据耗尽:返回
null
CAUTION
如果方法不返回 null
,会导致批处理陷入无限循环或错误终止!
✍️ ItemWriterAdapter 使用指南
核心配置(Kotlin DSL)
kotlin
@Configuration
class BatchConfig {
// 配置ItemWriter适配器
@Bean
fun itemWriter(): ItemWriterAdapter<Foo> {
return ItemWriterAdapter<Foo>().apply {
targetObject = fooService() // [!code highlight] // 绑定目标服务
targetMethod = "processFoo" // [!code highlight] // 指定处理方法
}
}
@Bean
fun fooService() = FooService()
}
class FooService {
// 处理方法:参数类型必须匹配写入的数据类型
fun processFoo(item: Foo) { // [!code warning] // 注意参数类型匹配
println("Processing: ${item.name}")
// 实际业务逻辑:保存到DB/发送消息等
}
}
方法签名要求
被适配的写入方法必须满足:
- 方法参数:单个对象或对象集合
- 返回类型:
void
或不返回
kotlin
// 适合小数据量场景
fun processItem(item: Foo) {
// 处理单个对象
}
kotlin
// 适合大数据量高效处理
fun processItems(items: List<Foo>) {
// 批量处理逻辑
}
🚫 常见错误与解决方案
错误1:忘记返回null导致无限循环
kotlin
// 错误实现 ❌
fun generateData(): Foo {
return Foo("data") // 总是返回对象,不会停止
}
// 正确实现 ✅
fun generateData(): Foo? {
return if (hasNext) Foo("data") else null
}
错误2:方法签名不匹配
kotlin
// 错误:ItemWriter需要处理对象集合 ❌
fun saveItem(item: Foo) { ... }
// 正确:参数类型匹配批处理数据 ✅
fun saveItems(items: List<Foo>) { ... }
WARNING
类型不匹配会导致 ClassCastException
运行时异常!
💡 最佳实践建议
- 隔离适配逻辑:为适配器创建专用配置类
- 方法命名规范:
- 读取方法:
generateXxx()
,fetchXxx()
- 写入方法:
processXxx()
,saveXxx()
- 读取方法:
- 空值处理:使用
Optional
避免NPE
kotlin
// 安全的读取方法实现
fun safeGenerate(): Foo? {
return try {
// 业务逻辑
} catch (e: Exception) {
null // 异常时返回null终止处理
}
}
- 性能优化:批量处理时配置合适的
chunk size
kotlin
@Bean
fun step(): Step {
return stepBuilderFactory.get("myStep")
.chunk<Foo, Foo>(50) // [!code highlight] // 每50条处理一次
.reader(itemReader())
.writer(itemWriter())
.build()
}
✅ 总结:重用服务的优势
方案 | 优点 | 适用场景 |
---|---|---|
ItemReaderAdapter | 复用数据生成逻辑 | 数据加载/转换 |
ItemWriterAdapter | 复用数据持久化逻辑 | 数据保存/推送 |
直接注入 | 简单直接 | 辅助逻辑处理 |
通过适配器模式,我们实现了:
- 逻辑复用:避免重复代码
- 架构统一:服务与批处理无缝集成
- 维护简化:业务变更只需修改服务实现
[!SUCCESS] Spring Batch 的适配器就像 万能转换插头,让现有服务轻松接入批处理系统,显著提升开发效率和系统一致性!