先说问题情况
系统环境
- java version: 17
- spring boot: 3.x
- spring cloud: 4.x
项目配置和代码
项目中使用了Spring Cloud Circuit Breaker
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>
在代码里面使用了@Bulkhead
避免远程服务出现问题或者性能低下时蔓延到当前服务导致当前服务出现资源耗尽。黑话就是解决爆炸半径问题。
@CircuitBreaker(name = "licenseService", fallbackMethod = "buildFallbackLicenseList")
@Bulkhead(name = "bulkheadLicenseService", fallbackMethod = "buildFallbackLicenseList")
public List<License> getLicensesByOrganization(String organizationId) {
LOGGER.info("find all licenses belong to {}", organizationId);
LicenseExample example = new LicenseExample();
example.createCriteria().andOrganizationIdEqualTo(organizationId);
return licenseMapper.selectByExample(example);
}
当我们运行调试业务时发现@Bulkhead
未生效, 代码也没报错,通过日志信息发现线程依然是tomcat的线程。另外从prometheus 指标也能反映@Bulkhead
未生效。
查看文档,我在Bulkhead pattern supporting里面发现需要io.github.resilience4j:resilience4j-bulkhead
,查看maven 依赖树确实没有io.github.resilience4j:resilience4j-bulkhead
,好吧我把它加到pom.xml
里
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-bulkhead</artifactId>
</dependency>
重新启动项目,测试发现问题依然没变
经过一番查找发现缺少org.aspectj:aspectjweaver
,so在pom.xml
中加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
why?
debug调试
解决问题后,回过头去分析为什么会应为没有org.aspectj:aspectjweaver
, @Bulkhead
就不生效
在io.github.resilience4j.springboot3.bulkhead.autoconfigure.AbstractBulkheadConfigurationOnMissingBean
发现了问题
@Bean
@Conditional(value = {AspectJOnClasspathCondition.class})
@ConditionalOnMissingBean
public BulkheadAspect bulkheadAspect(
BulkheadConfigurationProperties bulkheadConfigurationProperties,
ThreadPoolBulkheadRegistry threadPoolBulkheadRegistry,
BulkheadRegistry bulkheadRegistry,
@Autowired(required = false) List<BulkheadAspectExt> bulkHeadAspectExtList,
FallbackExecutor fallbackExecutor,
SpelResolver spelResolver) {
return bulkheadConfiguration
.bulkheadAspect(bulkheadConfigurationProperties, threadPoolBulkheadRegistry,
bulkheadRegistry, bulkHeadAspectExtList, fallbackExecutor, spelResolver);
}
要创建BulkheadAspect
需要经过AspectJOnClasspathCondition
条件判断,我们经入AspectJOnClasspathCondition
看看是怎么判断的
package io.github.resilience4j.spring6.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class AspectJOnClasspathCondition implements Condition {
private static final Logger logger = LoggerFactory.getLogger(AspectJOnClasspathCondition.class);
private static final String CLASS_TO_CHECK = "org.aspectj.lang.ProceedingJoinPoint";
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return AspectUtil.checkClassIfFound(context, CLASS_TO_CHECK, (e) -> logger
.debug("Aspects are not activated because AspectJ is not on the classpath."));
}
}
AspectJOnClasspathCondition
会检测org.aspectj.lang.ProceedingJoinPoint
是否出现在classpath中。
本地调试我们调整日志level就可以看到debug提示
2024-09-30T12:14:04.950+08:00 DEBUG 10525 --- [licensing-service] [ main] i.g.r.s.u.AspectJOnClasspathCondition : Aspects are not activated because AspectJ is not on the classpath.
2024-09-30T12:14:04.951+08:00 DEBUG 10525 --- [licensing-service] [ main] i.g.r.s.u.AspectJOnClasspathCondition : Aspects are not activated because AspectJ is not on the classpath.
ok到这里原因就一目了然了。当然文档写的不沟详细也是导致出现这个问题的原因。