diff --git a/pom.xml b/pom.xml index 56bd2f7..4295f4c 100644 --- a/pom.xml +++ b/pom.xml @@ -163,7 +163,7 @@ io.github.resilience4j - resilience4j-spring + resilience4j-spring-boot2 ${resilience4j-spring.version} provided diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java index f8e9389..bbf5d5f 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitAutoConfiguration.java @@ -4,8 +4,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import com.alibaba.csp.sentinel.SphU; import com.github.lianjiatech.retrofit.spring.boot.degrade.DegradeRuleRegister; +import com.github.lianjiatech.retrofit.spring.boot.degrade.Resilience4jDegradeRuleRegister; import com.github.lianjiatech.retrofit.spring.boot.degrade.SentinelDegradeRuleRegister; +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; @@ -16,6 +20,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; @@ -132,9 +137,18 @@ public RetrofitConfigBean retrofitConfigBean(ObjectProvider @Bean @ConditionalOnMissingBean - @ConditionalOnClass(com.alibaba.csp.sentinel.SphU.class) + @ConditionalOnClass(SphU.class) + @ConditionalOnProperty(name = "retrofit.degrade.degrade-type", havingValue = "sentinel") public DegradeRuleRegister sentinelDegradeRuleRegister(){ - return new SentinelDegradeRuleRegister(retrofitProperties.getDegrade()); + return new SentinelDegradeRuleRegister(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnClass(CircuitBreaker.class) + @ConditionalOnProperty(name = "retrofit.degrade.degrade-type", havingValue = "resilience4j") + public DegradeRuleRegister resilience4JDegradeRuleRegister(CircuitBreakerRegistry circuitBreakerRegistry){ + return new Resilience4jDegradeRuleRegister(circuitBreakerRegistry); } diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java index 3f995bf..8dc853a 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/core/RetrofitFactoryBean.java @@ -122,30 +122,16 @@ private void loadDegradeRules() { return; } Assert.notNull(degradeRuleRegister, "[DegradeRuleRegister] not found bean instance"); - DegradeType degradeType = degradeProperty.getDegradeType(); - switch (degradeType) { - case SENTINEL: { - Method[] methods = retrofitInterface.getMethods(); - List retrofitDegradeRuleList = - Arrays.stream(methods).map(this::convertSentinelRule).filter(Objects::nonNull).collect(Collectors.toList()); - degradeRuleRegister.batchRegister(retrofitDegradeRuleList); - break; - } - case RESILIENCE4J: { - break; - } - default: { - throw new IllegalArgumentException("Not currently supported! degradeType=" + degradeType); - } - - } - - + Method[] methods = retrofitInterface.getMethods(); + List retrofitDegradeRuleList = Arrays.stream(methods) + .map(this::convertSentinelRule) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + degradeRuleRegister.batchRegister(retrofitDegradeRuleList); } /** - * TODO 可以优化 和{@link com.github.lianjiatech.retrofit.spring.boot.degrade.SentinelDegradeRuleRegister#convert(com.github.lianjiatech.retrofit.spring.boot.degrade.RetrofitDegradeRule)}放到一起 - * Sentinel 规则转换器 + * 提取熔断规则,优先级为方法>类>默认 * @param method method * @return RetrofitDegradeRule */ @@ -164,19 +150,11 @@ private RetrofitDegradeRule convertSentinelRule(Method method) { } else { degrade = retrofitInterface.getAnnotation(Degrade.class); } - - if (degrade == null) { - return null; - } - - DegradeStrategy degradeStrategy = degrade.degradeStrategy(); BaseResourceNameParser resourceNameParser = retrofitConfigBean.getResourceNameParser(); String resourceName = resourceNameParser.parseResourceName(method, environment); - RetrofitDegradeRule degradeRule = new RetrofitDegradeRule(); - degradeRule.setCount(degrade.count()); - degradeRule.setDegradeStrategy(degradeStrategy); - degradeRule.setTimeWindow(degrade.timeWindow()); + degradeRule.setCount(Optional.ofNullable(degrade).map(Degrade::count).orElse(null)); + degradeRule.setTimeWindow(Optional.ofNullable(degrade).map(Degrade::timeWindow).orElse(null)); degradeRule.setResourceName(resourceName); return degradeRule; } @@ -303,25 +281,11 @@ private synchronized OkHttpClient getOkHttpClient(Class retrofitClientInterfa // TODO 这里稍微有点问题,开启熔断则所有实例都会加熔断拦截器,但是拦截器升不生效则取决于是否配置了@Degrade注解,可不可以把这里做成有一个全局默认配置,有@Degrade则走单独配置? DegradeProperty degradeProperty = retrofitProperties.getDegrade(); if (degradeProperty.isEnable()) { - DegradeType degradeType = degradeProperty.getDegradeType(); - switch (degradeType) { - case SENTINEL: { - try { - Class.forName("com.alibaba.csp.sentinel.SphU"); - DegradeInterceptor degradeInterceptor = new DegradeInterceptor(); - degradeInterceptor.setEnvironment(environment); - degradeInterceptor.setResourceNameParser(retrofitConfigBean.getResourceNameParser()); - degradeInterceptor.setDegradeRuleRegister(retrofitConfigBean.getDegradeRuleRegister()); - okHttpClientBuilder.addInterceptor(degradeInterceptor); - } catch (ClassNotFoundException e) { - logger.warn("com.alibaba.csp.sentinel not found! No SentinelDegradeInterceptor is set."); - } - break; - } - default: { - throw new IllegalArgumentException("Not currently supported! degradeType=" + degradeType); - } - } + DegradeInterceptor degradeInterceptor = new DegradeInterceptor(); + degradeInterceptor.setEnvironment(environment); + degradeInterceptor.setResourceNameParser(retrofitConfigBean.getResourceNameParser()); + degradeInterceptor.setDegradeRuleRegister(retrofitConfigBean.getDegradeRuleRegister()); + okHttpClientBuilder.addInterceptor(degradeInterceptor); } // add ServiceInstanceChooserInterceptor diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Degrade.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Degrade.java index febad15..bef4491 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Degrade.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Degrade.java @@ -3,7 +3,8 @@ import java.lang.annotation.*; /** - * @author 陈添明 + * 应仅采用异常比例模式来控制熔断,超时导致的报错应在okhttp这一层做 + * @author 陈添明 yukdawn@gmail.com */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) @@ -11,17 +12,12 @@ public @interface Degrade { /** - * RT threshold or exception ratio threshold count. + * 异常比例 */ - double count(); + float count(); /** - * Degrade recover timeout (in seconds) when degradation occurs. + * 时间窗口size,单位:秒 */ int timeWindow() default 5; - - /** - * Degrade strategy (0: average RT, 1: exception ratio). - */ - DegradeStrategy degradeStrategy() default DegradeStrategy.AVERAGE_RT; } diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeRuleRegister.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeRuleRegister.java index 5266514..742260c 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeRuleRegister.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeRuleRegister.java @@ -3,16 +3,27 @@ import java.io.IOException; import java.util.List; +import okhttp3.Response; + /** * @author yukdawn@gmail.com 2022/4/5 23:14 */ public interface DegradeRuleRegister { - void register(RetrofitDegradeRule retrofitDegradeRule); - + /** + * 批量注册规则 + * @param retrofitDegradeRuleList 规则描述对象集合 + */ void batchRegister(List retrofitDegradeRuleList); - T exec(String resourceName, DegradeProxyMethod func) throws IOException; + /** + * 使用规则代理执行目标方法 + * @param resourceName 资源名称 + * @param func 目标方法 + * @return okhttp响应 + * @throws IOException IOException + */ + Response exec(String resourceName, DegradeProxyMethod func) throws IOException; @FunctionalInterface interface DegradeProxyMethod{ diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeStrategy.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeStrategy.java deleted file mode 100644 index d33ed4c..0000000 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeStrategy.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.lianjiatech.retrofit.spring.boot.degrade; - -/** - * @author 陈添明 - */ -public enum DegradeStrategy { - - /** - * average RT - */ - AVERAGE_RT, - - /** - * exception ratio - */ - EXCEPTION_RATIO, -} diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Resilience4jDegradeRuleRegister.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Resilience4jDegradeRuleRegister.java new file mode 100644 index 0000000..644517a --- /dev/null +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Resilience4jDegradeRuleRegister.java @@ -0,0 +1,89 @@ +package com.github.lianjiatech.retrofit.spring.boot.degrade; + +import java.io.IOException; +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.github.resilience4j.circuitbreaker.CallNotPermittedException; +import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; +import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry; +import io.github.resilience4j.core.StopWatch; +import okhttp3.Response; +import org.springframework.util.CollectionUtils; + +/** + * @author yukdawn@gmail.com 2022/4/5 23:15 + */ +public class Resilience4jDegradeRuleRegister implements DegradeRuleRegister{ + + private final CircuitBreakerRegistry circuitBreakerRegistry; + + public Resilience4jDegradeRuleRegister(CircuitBreakerRegistry circuitBreakerRegistry) { + this.circuitBreakerRegistry = circuitBreakerRegistry; + } + + @Override + public void batchRegister(List ruleList) { + if (CollectionUtils.isEmpty(ruleList)){ + return; + } + for (RetrofitDegradeRule rule : ruleList) { + circuitBreakerRegistry.circuitBreaker(rule.getResourceName(), this.convert(rule)); + } + + } + + @Override + public Response exec(String resourceName, DegradeProxyMethod func) throws IOException { + CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(resourceName); + System.out.println("当前断路器状态: "+ circuitBreaker.getState()); + + final StopWatch stopWatch = StopWatch.start(); + try { + circuitBreaker.acquirePermission(); + final Response response = func.get(); + circuitBreaker.onResult(stopWatch.stop().toNanos(), TimeUnit.NANOSECONDS, response); + return response; + }catch (CallNotPermittedException e){ + throw new RetrofitBlockException(e); + } catch (Exception exception) { + circuitBreaker.onError(stopWatch.stop().toNanos(), TimeUnit.NANOSECONDS, exception); + throw exception; + } + } + + private CircuitBreakerConfig convert(RetrofitDegradeRule rule){ + // add degrade rule + CircuitBreakerConfig.Builder circuitBreakerBuilder = CircuitBreakerConfig.from(newInstanceByDefault()); + if (Objects.nonNull(rule.getCount())){ + circuitBreakerBuilder.failureRateThreshold(rule.getCount()); + } + if (Objects.nonNull(rule.getTimeWindow())){ + circuitBreakerBuilder.slidingWindowSize(rule.getTimeWindow()); + } + return circuitBreakerBuilder.build(); + } + + public CircuitBreakerConfig newInstanceByDefault(){ + // 断路器配置 + return CircuitBreakerConfig.custom() + // 滑动窗口的类型为时间窗口 + .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.TIME_BASED) + // 时间窗口的大小为60秒 + .slidingWindowSize(60) + // 在单位时间窗口内最少需要10次调用才能开始进行统计计算 + .minimumNumberOfCalls(10) + // 在单位时间窗口内调用失败率达到60%后会启动断路器 + .failureRateThreshold(60) + // 允许断路器自动由打开状态转换为半开状态 + .enableAutomaticTransitionFromOpenToHalfOpen() + // 在半开状态下允许进行正常调用的次数 + .permittedNumberOfCallsInHalfOpenState(5) + // 断路器打开状态转换为半开状态需要等待60秒 + .waitDurationInOpenState(Duration.ofSeconds(60)) + .build(); + } +} diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/RetrofitDegradeRule.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/RetrofitDegradeRule.java index 757a4d4..c78ce23 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/RetrofitDegradeRule.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/RetrofitDegradeRule.java @@ -7,11 +7,9 @@ public class RetrofitDegradeRule { private String resourceName; - private double count; + private Float count; - private int timeWindow; - - private DegradeStrategy degradeStrategy; + private Integer timeWindow; public String getResourceName() { return resourceName; @@ -21,27 +19,20 @@ public void setResourceName(String resourceName) { this.resourceName = resourceName; } - public double getCount() { + public Float getCount() { return count; } - public void setCount(double count) { + public void setCount(Float count) { this.count = count; } - public int getTimeWindow() { + public Integer getTimeWindow() { return timeWindow; } - public void setTimeWindow(int timeWindow) { + public void setTimeWindow(Integer timeWindow) { this.timeWindow = timeWindow; } - public DegradeStrategy getDegradeStrategy() { - return degradeStrategy; - } - - public void setDegradeStrategy(DegradeStrategy degradeStrategy) { - this.degradeStrategy = degradeStrategy; - } } diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeRuleRegister.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeRuleRegister.java index 44beec2..c1935cb 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeRuleRegister.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeRuleRegister.java @@ -2,6 +2,8 @@ import java.io.IOException; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import com.alibaba.csp.sentinel.Entry; @@ -9,12 +11,10 @@ import com.alibaba.csp.sentinel.ResourceTypeConstants; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.alibaba.csp.sentinel.slots.block.RuleConstant; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; -import com.github.lianjiatech.retrofit.spring.boot.config.DegradeProperty; -import com.github.lianjiatech.retrofit.spring.boot.exception.RetrofitException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import okhttp3.Response; import org.springframework.util.CollectionUtils; /** @@ -22,19 +22,6 @@ */ public class SentinelDegradeRuleRegister implements DegradeRuleRegister{ - private final static Logger logger = LoggerFactory.getLogger(SentinelDegradeRuleRegister.class); - - private final DegradeProperty degradeProperty; - - public SentinelDegradeRuleRegister(DegradeProperty degradeProperty) { - this.degradeProperty = degradeProperty; - } - - @Override - public void register(RetrofitDegradeRule retrofitDegradeRule) { - throw new RetrofitException("sentinel not supported simple register"); - } - @Override public void batchRegister(List retrofitDegradeRuleList) { if (CollectionUtils.isEmpty(retrofitDegradeRuleList)){ @@ -44,7 +31,7 @@ public void batchRegister(List retrofitDegradeRuleList) { } @Override - public T exec(String resourceName, DegradeProxyMethod func) throws IOException { + public Response exec(String resourceName, DegradeProxyMethod func) throws IOException { Entry entry = null; try { entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.OUT); @@ -59,30 +46,24 @@ public T exec(String resourceName, DegradeProxyMethod func) throws IOExce } private DegradeRule convert(RetrofitDegradeRule retrofitDegradeRule){ - DegradeStrategy degradeStrategy = retrofitDegradeRule.getDegradeStrategy(); - int grade; - switch (degradeStrategy) { - case AVERAGE_RT: { - grade = 0; - break; - } - case EXCEPTION_RATIO: { - grade = 1; - break; - } - default: { - throw new IllegalArgumentException("Not currently supported! degradeStrategy=" + degradeStrategy); - } - } - String resourceName = retrofitDegradeRule.getResourceName(); // add degrade rule - DegradeRule rule = new DegradeRule() - .setGrade(grade) - // Max allowed response time - .setCount(retrofitDegradeRule.getCount()) - // Retry timeout (in second) - .setTimeWindow(retrofitDegradeRule.getTimeWindow()); - rule.setResource(resourceName); + DegradeRule rule = defaultRuleNewInstance(); + if (Objects.nonNull(retrofitDegradeRule.getTimeWindow())){ + rule.setTimeWindow(retrofitDegradeRule.getTimeWindow()); + } + rule.setCount(rule.getTimeWindow() * + Optional.ofNullable(retrofitDegradeRule.getCount()).orElse(0.6F)); + rule.setResource(retrofitDegradeRule.getResourceName()); return rule; } + + public DegradeRule defaultRuleNewInstance(){ + return new DegradeRule() + // 使用异常数量策略,做个中转实现异常比例,异常比例策略在sentinel的实现为每秒检测,不是根据时间窗口来 + .setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) + // 异常比例 + .setCount(60*0.6) + // 时间窗口 + .setTimeWindow(60); + } } diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/retry/DefaultRetryInterceptor.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/retry/DefaultRetryInterceptor.java index f99df58..5bc0a11 100644 --- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/retry/DefaultRetryInterceptor.java +++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/retry/DefaultRetryInterceptor.java @@ -42,6 +42,7 @@ protected Response retryIntercept(int maxRetries, int intervalMs, RetryRule[] re if (shouldThrowEx(retryRuleSet, e)) { throw new RuntimeException(e); } else { + // TODO 这里应该还把最后一次的原始错误也要抛出来 if (!retryStrategy.shouldRetry()) { // 最后一次还没成功,抛出异常 throw new RuntimeException("Retry Failed: Total " + maxRetries diff --git a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitStarterTest.java b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitStarterTest.java index 5411f6c..3b4465b 100644 --- a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitStarterTest.java +++ b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/RetrofitStarterTest.java @@ -9,6 +9,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; import com.github.lianjiatech.retrofit.spring.boot.test.http.HttpApi4; import org.junit.After; @@ -424,22 +425,29 @@ public void testBoolean() { @Test public void testDegrade() { - for (int i = 0; i < 10; i++) { + IntStream.range(0, 100).parallel().forEach((i) ->{ try { + Person mockPerson = new Person().setId(1L) + .setName("test") + .setAge(10); + Result mockResult = new Result<>() + .setCode(0) + .setMsg("ok") + .setData(mockPerson); MockResponse response = new MockResponse() - .setResponseCode(400) + .setResponseCode(200) .addHeader("Content-Type", "application/text; charset=utf-8") .addHeader("Cache-Control", "no-cache") - .setBody("false") + .setBody(objectMapper.writeValueAsString(mockResult)) .setHeadersDelay(5, TimeUnit.SECONDS); server.enqueue(response); System.out.println(httpApi4.getPerson(2L).getCode()); }catch (Exception e){ - System.out.println(e.getMessage()); + System.out.println("抛出异常:" + e.getMessage()); }finally { System.out.println("当前请求轮次: "+ (i+1)); } - } + }); } diff --git a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi4.java b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi4.java index b9f5d47..e6b12b8 100644 --- a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi4.java +++ b/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi4.java @@ -15,7 +15,7 @@ * @author 陈添明 */ @RetrofitClient(baseUrl = "${test.baseUrl}", fallbackFactory = HttpApi4.HttpDegradeFallbackFactory.class) -@Degrade(count = 0.5) +@Degrade(count = 0.5F) public interface HttpApi4 { /** @@ -24,7 +24,7 @@ public interface HttpApi4 { * @param id . * @return . */ - @GET("/degrade/person") + @GET("degrade/person") Result getPerson(@Query("id") Long id); @Service diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 70495cb..3115af8 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -54,7 +54,7 @@ retrofit: # 是否启用熔断降级 enable: true # 熔断降级实现方式 - degrade-type: sentinel + degrade-type: resilience4j # 熔断资源名称解析器 resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser # 全局连接超时时间