如何创建拦截器监听列表修改,自动同步更新QaService产品类型?
通用实现方案
提供两种落地方式,可根据你的项目场景选择:
方案1:封装可监听的可变列表(侵入性最低,无遗漏)
核心思路是代理MutableList的所有修改方法,操作执行完成后自动触发校验逻辑,从根源上避免新增修改方法时遗漏校验。
步骤1:通用化拦截器实现
import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component // 泛型化拦截器,支持任意元素类型的列表 @Component class ListProductInterceptor { @Autowired private lateinit var qaService: QaService fun <T> intercept(productType: ProductTypeEnum, list: List<T>) { if (list.isEmpty()) { qaService.removeProductType(productType) } else if (!qaService.typeList.contains(productType)) { qaService.addProductType(productType) } } }
步骤2:封装可自动触发拦截的列表实现
class ObservableMutableList<T>( private val productType: ProductTypeEnum, private val delegate: MutableList<T> = mutableListOf(), // 从Spring上下文获取拦截器实例,或者构造时传入 private val interceptor: ListProductInterceptor = SpringContextUtil.getBean(ListProductInterceptor::class.java) ) : MutableList<T> by delegate { private fun afterModify() { interceptor.intercept(productType, this) } override fun add(element: T): Boolean { return delegate.add(element).also { afterModify() } } override fun add(index: Int, element: T) { delegate.add(index, element).also { afterModify() } } override fun addAll(elements: Collection<T>): Boolean { return delegate.addAll(elements).also { afterModify() } } override fun addAll(index: Int, elements: Collection<T>): Boolean { return delegate.addAll(index, elements).also { afterModify() } } override fun remove(element: T): Boolean { return delegate.remove(element).also { afterModify() } } override fun removeAt(index: Int): T { return delegate.removeAt(index).also { afterModify() } } override fun removeAll(elements: Collection<T>): Boolean { return delegate.removeAll(elements).also { afterModify() } } override fun retainAll(elements: Collection<T>): Boolean { return delegate.retainAll(elements).also { afterModify() } } override fun clear() { delegate.clear().also { afterModify() } } }
步骤3:业务层使用
直接替换原有MutableList定义即可,所有列表操作都会自动触发校验,无需在每个业务方法中写重复逻辑:
class WarehouseService: IWarehouseService { // 直接定义为监听列表,指定对应的产品类型即可 val tiles = ObservableMutableList<Tile>(ProductTypeEnum.Tile) // 其他类型的列表同理 val woods = ObservableMutableList<Wood>(ProductTypeEnum.Wood) override fun destroyProduct() { // 仅处理业务逻辑,无需手动加校验 tiles.removeLast() } }
方案2:Spring AOP切面实现(适合存量业务改造)
如果不想修改现有列表的定义,可通过切面加注解的方式实现,仅需要给修改列表的方法加注解即可。
步骤1:定义标记注解
@Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class SyncProductType( val productType: ProductTypeEnum, val listFieldName: String // 指定要校验的列表字段名 )
步骤2:实现切面逻辑
@Aspect @Component class ProductTypeSyncAspect { @Autowired private lateinit var qaService: QaService @After("@annotation(syncProductType)") fun afterModifyList(joinPoint: JoinPoint, syncProductType: SyncProductType) { val target = joinPoint.target // 反射获取对应的列表字段 val listField = target::class.java.getDeclaredField(syncProductType.listFieldName) listField.isAccessible = true val list = listField.get(target) as List<*> // 执行校验逻辑 val productType = syncProductType.productType if (list.isEmpty()) { qaService.removeProductType(productType) } else if (!qaService.typeList.contains(productType)) { qaService.addProductType(productType) } } }
步骤3:业务层使用
在所有修改对应列表的方法上加注解即可,新增方法只要加注解就不会遗漏校验:
class WarehouseService: IWarehouseService { val tiles = mutableListOf<Tile>() val woods = mutableListOf<Wood>() @SyncProductType(productType = ProductTypeEnum.Tile, listFieldName = "tiles") override fun destroyProduct() { // 仅处理业务逻辑 tiles.removeLast() } @SyncProductType(productType = ProductTypeEnum.Wood, listFieldName = "woods") override fun addWood() { woods.add(Wood()) } }
方案选型建议
- 优先选方案1:无额外注解成本,所有列表操作(包括直接调用列表的add/remove等方法)都会触发校验,不会出现遗漏
- 若为存量项目,大量业务逻辑已经写完不想改动列表定义,可选方案2
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

