同一类内调用@Bulkhead方法未生效,线程为何顺序执行?
问题原因分析
这是Spring AOP代理机制导致的典型问题,Resilience4j的@Bulkhead注解基于Spring AOP实现,只有通过代理对象调用被注解的方法时,注解对应的限流/隔离逻辑才会生效。
具体原因拆解
- 跨类调用时:你拿到的是Spring容器管理的代理对象(JDK动态代理或CGLIB代理),调用方法会先经过代理类的拦截逻辑,触发
@Bulkhead的隔离规则,所以多线程调用能正常并行执行。 - 同类内部调用时:本质是通过
this引用直接调用原始对象的方法,完全没经过Spring生成的代理类。此时@Bulkhead的切面逻辑不会被触发,方法就像普通无注解方法一样执行。如果方法内部有阻塞操作(比如restTemplate.getForObject()),线程会依次等待执行,最终表现为顺序执行的效果。
验证方式
你可以在类内调用时,从Spring容器获取当前类的代理对象再调用方法,就能看到@Bulkhead生效:
// 注入ApplicationContext @Autowired private ApplicationContext context; // 类内调用时使用代理对象 for (int i=0; i<10; i++) { new Thread(() -> context.getBean(UserServiceApplication.class).testBulkhead()).start(); }
解决方案
- 通过代理对象调用:从Spring容器中获取当前类的代理实例,而非直接用
this调用。 - 重构代码:将被
@Bulkhead注解的方法抽离到单独的服务类中,原类注入该服务类后调用。 - 注入自身代理对象:在当前类中用
@Autowired注入自己(Spring会注入代理对象),通过这个实例调用方法:
@Autowired private UserServiceApplication self; // 调用时使用self而非this self.testBulkhead();
内容的提问来源于stack exchange,提问作者myfidan
相关产品推荐
相关产品推荐

