Spring Batch如何拦截抽象父类中定义的ItemWriter write方法?
问题场景:Spring批处理ItemWriter的write方法拦截异常
对批处理应用做系统测试时,需要在测试类内调控作业步骤运行行为,尝试给步骤Bean挂载MethodInterceptor,比如给writer Bean添加可抛出异常的拦截器。
现有Writer类的继承结构如下:
public abstract class Abstractwriter implements ItemWriter { ... @Override public void write(){ //writing } } public class Xyzwriter extends Abstractwriter { public void someMethod(){ //dowhat } }
注意:write方法仅在抽象父类中完成重写实现,子类Xyzwriter没有重写该方法。
尝试的实现与遇到的问题
第一次实现
自定义BeanPostProcessor,在配置类中为writer Bean的write方法挂载拦截器:
myBeanPostProcessor.getMap().put("Xyzwriter", dangerousWriterInterceptor);
MyBeanPostProcessor实现如下:
public class MyBeanPostProcessor implements BeanPostProcessor { private Map<String , MyInterceptoredBeanType> map = new HashMap<>(); @Override public Object postProcessAfterInitialization(Object bean, String intercepedBeanName) throws BeansException { if ( map.get(intercepedBeanName) != null ){ return map.get(intercepedBeanName); } return bean; } }
测试流程:Spring上下文加载完成后,切换dangerousWriterInterceptor的抛异常开关,再启动作业。
抛出NoSuchMethodException,原因是write方法仅定义在抽象父类中,子类Xyzwriter没有该方法的实现,拦截器匹配子类方法失败。
第二次实现
在Xyzwriter中重写write方法,内部直接调用super.write(args):
public class XYZwriter extends Abstractwriter { @Override public void write(){ super.write(args); } }
此时抛出新错误:
nested exception is java.lang.IllegalArgumentException: found more than one method on target class[XYZwriter$$EnhancerBySpringCGLIB$$1052d06a] with the annotation type [BeforeStep].
原因是直接替换Bean实例的代理方式和Spring原生代理冲突,导致注解被重复扫描。
解决方案
- 回滚子类的write方法重写,移除Xyzwriter中新增的write方法,避免父类和子类的同签名方法在代理时产生冲突。
- 修正MethodInterceptor的匹配规则,不需要限定查找子类自身声明的方法,匹配ItemWriter接口定义的write方法即可:
new StaticMethodMatcherPointcut() { @Override public boolean matches(Method method, Class<?> targetClass) { return "write".equals(method.getName()) && ItemWriter.class.isAssignableFrom(method.getDeclaringClass()); } }
- 调整BeanPostProcessor的代理逻辑,不要直接替换整个Bean实例,在原有Bean的基础上追加拦截器,避免覆盖Spring原生代理导致注解冲突,修正后的实现参考:
public class MyBeanPostProcessor implements BeanPostProcessor { private Map<String, MethodInterceptor> interceptorMap = new HashMap<>(); @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { MethodInterceptor interceptor = interceptorMap.get(beanName); if (interceptor == null) { return bean; } // 基于原有Bean生成代理,追加自定义拦截器 ProxyFactory proxyFactory = new ProxyFactory(bean); proxyFactory.addAdvisor(new DefaultPointcutAdvisor(writePointcut(), interceptor)); return proxyFactory.getProxy(); } private Pointcut writePointcut() { return new StaticMethodMatcherPointcut() { @Override public boolean matches(Method method, Class<?> targetClass) { return "write".equals(method.getName()) && ItemWriter.class.isAssignableFrom(method.getDeclaringClass()); } }; } public Map<String, MethodInterceptor> getInterceptorMap() { return interceptorMap; } }
内容的提问来源于stack exchange,提问作者saab
相关产品推荐
相关产品推荐

