Spring Boot应用使用Cglib时抛出InvocationTargetException问题
解决CGLIB动态代理实体时toString()方法的InvocationTargetException问题
我之前也踩过CGLIB代理递归调用的坑,你的问题本质是代理对象的方法调用触发了无限递归拦截,最终抛出InvocationTargetException。比如IDE调试时会自动调用toString(),而你当前的拦截逻辑里,每次执行method.invoke(obj, args)都是在调用代理对象的方法,这会再次触发intercept方法,循环往复直到栈溢出,就出现了这个报错。
问题根源拆解
你当前的intercept方法没有区分目标方法,不管是toString()、hashCode()还是普通getter,只要调用代理对象的方法就会进入拦截器。当调用toString()时,会无限触发拦截逻辑,形成递归死循环,最终抛出异常。
修复方案
我们需要精准控制拦截范围:只对需要懒加载的方法(比如getTerminals)做特殊处理,其他方法直接转发给原始的Airport实体对象,彻底避免递归调用。
修改后的AirportInterceptor代码如下:
class AirportInterceptor implements MethodInterceptor { private TerminalMapper terminalMapper; private Airport airport; public AirportInterceptor(Airport airport, TerminalMapper terminalMapper) { this.airport = airport; this.terminalMapper = terminalMapper; } @Override public Object intercept(Object proxyObj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 仅对需要懒加载的getTerminals方法做处理 if ("getTerminals".equals(method.getName())) { // 直接检查原始实体的属性,避免触发代理方法的递归 if (airport.getTerminals() == null) { List<Terminal> terminals = terminalMapper.findByAirportCode(airport.getId()); airport.setTerminals(terminals); } // 返回原始实体的属性值,跳过代理方法调用 return airport.getTerminals(); } // 所有其他方法(toString、hashCode、其他非懒加载getter等)直接调用原始实体的方法 return method.invoke(airport, args); } public void saveChanges() { // 这里注意需要注入或通过构造传入airportMapper airportMapper.update(this.airport); } }
关键修改说明
- 切断递归链条:所有非懒加载方法都直接调用原始
airport实体的方法,不再触发拦截器,从根源上解决了toString()这类方法的递归问题。 - 精准拦截目标:只对
getTerminals做懒加载逻辑,其他方法完全复用原始实体的实现,保证原有行为不变。 - 优化空值判断:直接用原始实体的
getTerminals()判断是否需要加载,避免调用代理对象的方法触发不必要的拦截。
另外,你在AirportsRepository中保存airportInterceptors的逻辑是合理的,后续批量同步变更时,遍历这些拦截器调用saveChanges()就能把原始实体的更新同步到数据库。
内容的提问来源于stack exchange,提问作者BigONotation
相关产品推荐
相关产品推荐

