diff --git a/pom.xml b/pom.xml
index 4295f4c..84224ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,7 +46,6 @@
1.17.5
1.6.3
2.12.6.1
- 1.7.1
@@ -160,14 +159,6 @@
${sentinel.version}
provided
-
-
- io.github.resilience4j
- 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 bbf5d5f..34c3824 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,23 +4,14 @@
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;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
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;
@@ -38,6 +29,7 @@
import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitFactoryBean;
import com.github.lianjiatech.retrofit.spring.boot.core.ServiceInstanceChooser;
import com.github.lianjiatech.retrofit.spring.boot.degrade.BaseResourceNameParser;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.RetrofitDegradeRuleInitializer;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.GlobalAndNetworkInterceptorFinder;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.ServiceInstanceChooserInterceptor;
import com.github.lianjiatech.retrofit.spring.boot.retry.BaseRetryInterceptor;
@@ -79,7 +71,7 @@ public GlobalAndNetworkInterceptorFinder globalAndNetworkInterceptorFinder() {
@Bean
@ConditionalOnMissingBean
- public RetrofitConfigBean retrofitConfigBean(ObjectProvider degradeRuleRegisterObjectProvider) throws IllegalAccessException, InstantiationException {
+ public RetrofitConfigBean retrofitConfigBean() throws IllegalAccessException, InstantiationException {
RetrofitConfigBean retrofitConfigBean =
new RetrofitConfigBean(retrofitProperties, globalAndNetworkInterceptorFinder());
// Initialize the connection pool
@@ -129,28 +121,9 @@ public RetrofitConfigBean retrofitConfigBean(ObjectProvider
Class extends BaseResourceNameParser> resourceNameParser = degrade.getResourceNameParser();
retrofitConfigBean.setResourceNameParser(resourceNameParser.newInstance());
- // degrade register
- retrofitConfigBean.setDegradeRuleRegister(degradeRuleRegisterObjectProvider.getIfAvailable());
-
return retrofitConfigBean;
}
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnClass(SphU.class)
- @ConditionalOnProperty(name = "retrofit.degrade.degrade-type", havingValue = "sentinel")
- public DegradeRuleRegister sentinelDegradeRuleRegister(){
- 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);
- }
-
@Bean
@ConditionalOnMissingBean
@@ -172,6 +145,11 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
this.applicationContext = applicationContext;
}
+ @Bean
+ public RetrofitDegradeRuleInitializer retrofitDegradeRuleInitializer() {
+ return new RetrofitDegradeRuleInitializer(retrofitProperties.getDegrade());
+ }
+
@Configuration
@Import({AutoConfiguredRetrofitScannerRegistrar.class})
@ConditionalOnMissingBean(RetrofitFactoryBean.class)
diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java
index fac4639..4f55b4f 100644
--- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java
+++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/config/RetrofitConfigBean.java
@@ -4,7 +4,6 @@
import java.util.Map;
import com.github.lianjiatech.retrofit.spring.boot.degrade.BaseResourceNameParser;
-import com.github.lianjiatech.retrofit.spring.boot.degrade.DegradeRuleRegister;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.GlobalAndNetworkInterceptorFinder;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.GlobalInterceptor;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.NetworkInterceptor;
@@ -38,8 +37,6 @@ public class RetrofitConfigBean {
private BaseResourceNameParser resourceNameParser;
- private DegradeRuleRegister degradeRuleRegister;
-
public RetrofitProperties getRetrofitProperties() {
return retrofitProperties;
}
@@ -108,12 +105,4 @@ public BaseResourceNameParser getResourceNameParser() {
public void setResourceNameParser(BaseResourceNameParser resourceNameParser) {
this.resourceNameParser = resourceNameParser;
}
-
- public DegradeRuleRegister getDegradeRuleRegister() {
- return degradeRuleRegister;
- }
-
- public void setDegradeRuleRegister(DegradeRuleRegister degradeRuleRegister) {
- this.degradeRuleRegister = degradeRuleRegister;
- }
}
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 8dc853a..f97c8de 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
@@ -6,11 +6,14 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import com.github.lianjiatech.retrofit.spring.boot.degrade.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
@@ -33,6 +36,14 @@
import com.github.lianjiatech.retrofit.spring.boot.config.LogProperty;
import com.github.lianjiatech.retrofit.spring.boot.config.RetrofitConfigBean;
import com.github.lianjiatech.retrofit.spring.boot.config.RetrofitProperties;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.BaseResourceNameParser;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.Degrade;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.DegradeStrategy;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.DegradeType;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.FallbackFactory;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.RetrofitDegradeRule;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.RetrofitDegradeRuleInitializer;
+import com.github.lianjiatech.retrofit.spring.boot.degrade.SentinelDegradeInterceptor;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BaseLoggingInterceptor;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BasePathMatchInterceptor;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.ErrorDecoderInterceptor;
@@ -62,7 +73,7 @@ public class RetrofitFactoryBean implements FactoryBean, EnvironmentAware,
private static final Map, CallAdapter.Factory> CALL_ADAPTER_FACTORIES_CACHE =
new HashMap<>(4);
- private final Class retrofitInterface;
+ private Class retrofitInterface;
private Environment environment;
@@ -72,7 +83,7 @@ public class RetrofitFactoryBean implements FactoryBean, EnvironmentAware,
private ApplicationContext applicationContext;
- private final RetrofitClient retrofitClient;
+ private RetrofitClient retrofitClient;
private static final Map, Converter.Factory> CONVERTER_FACTORIES_CACHE =
new HashMap<>(4);
@@ -111,52 +122,40 @@ public T getObject() throws Exception {
);
}
- /**
- * 加载熔断配置,熔断粒度可控制到方法级别
- */
private void loadDegradeRules() {
- DegradeProperty degradeProperty = retrofitProperties.getDegrade();
- DegradeRuleRegister degradeRuleRegister = retrofitConfigBean.getDegradeRuleRegister();
-
- if (!degradeProperty.isEnable()) {
- return;
- }
- Assert.notNull(degradeRuleRegister, "[DegradeRuleRegister] not found bean instance");
+ // 读取熔断配置
Method[] methods = retrofitInterface.getMethods();
- List retrofitDegradeRuleList = Arrays.stream(methods)
- .map(this::convertSentinelRule)
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
- degradeRuleRegister.batchRegister(retrofitDegradeRuleList);
- }
+ for (Method method : methods) {
+ if (method.isDefault()) {
+ continue;
+ }
+ int modifiers = method.getModifiers();
+ if (Modifier.isStatic(modifiers)) {
+ continue;
+ }
+ // 获取熔断配置
+ Degrade degrade;
+ if (method.isAnnotationPresent(Degrade.class)) {
+ degrade = method.getAnnotation(Degrade.class);
+ } else {
+ degrade = retrofitInterface.getAnnotation(Degrade.class);
+ }
- /**
- * 提取熔断规则,优先级为方法>类>默认
- * @param method method
- * @return RetrofitDegradeRule
- */
- private RetrofitDegradeRule convertSentinelRule(Method method) {
- if (method.isDefault()) {
- return null;
- }
- int modifiers = method.getModifiers();
- if (Modifier.isStatic(modifiers)) {
- return null;
- }
- // 获取熔断配置
- Degrade degrade;
- if (method.isAnnotationPresent(Degrade.class)) {
- degrade = method.getAnnotation(Degrade.class);
- } else {
- degrade = retrofitInterface.getAnnotation(Degrade.class);
+ if (degrade == null) {
+ continue;
+ }
+
+ 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.setResourceName(resourceName);
+ RetrofitDegradeRuleInitializer.addRetrofitDegradeRule(degradeRule);
}
- BaseResourceNameParser resourceNameParser = retrofitConfigBean.getResourceNameParser();
- String resourceName = resourceNameParser.parseResourceName(method, environment);
- RetrofitDegradeRule degradeRule = new RetrofitDegradeRule();
- 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;
}
/**
@@ -278,14 +277,26 @@ private synchronized OkHttpClient getOkHttpClient(Class> retrofitClientInterfa
}
// add DegradeInterceptor
- // TODO 这里稍微有点问题,开启熔断则所有实例都会加熔断拦截器,但是拦截器升不生效则取决于是否配置了@Degrade注解,可不可以把这里做成有一个全局默认配置,有@Degrade则走单独配置?
DegradeProperty degradeProperty = retrofitProperties.getDegrade();
if (degradeProperty.isEnable()) {
- DegradeInterceptor degradeInterceptor = new DegradeInterceptor();
- degradeInterceptor.setEnvironment(environment);
- degradeInterceptor.setResourceNameParser(retrofitConfigBean.getResourceNameParser());
- degradeInterceptor.setDegradeRuleRegister(retrofitConfigBean.getDegradeRuleRegister());
- okHttpClientBuilder.addInterceptor(degradeInterceptor);
+ DegradeType degradeType = degradeProperty.getDegradeType();
+ switch (degradeType) {
+ case SENTINEL: {
+ try {
+ Class.forName("com.alibaba.csp.sentinel.SphU");
+ SentinelDegradeInterceptor sentinelDegradeInterceptor = new SentinelDegradeInterceptor();
+ sentinelDegradeInterceptor.setEnvironment(environment);
+ sentinelDegradeInterceptor.setResourceNameParser(retrofitConfigBean.getResourceNameParser());
+ okHttpClientBuilder.addInterceptor(sentinelDegradeInterceptor);
+ } 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);
+ }
+ }
}
// add ServiceInstanceChooserInterceptor
diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeInterceptor.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/BaseDegradeInterceptor.java
similarity index 72%
rename from src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeInterceptor.java
rename to src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/BaseDegradeInterceptor.java
index 1519bbb..547af27 100644
--- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeInterceptor.java
+++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/BaseDegradeInterceptor.java
@@ -12,18 +12,12 @@
/**
* @author 陈添明
*/
-public class DegradeInterceptor implements Interceptor {
+public abstract class BaseDegradeInterceptor implements Interceptor {
private Environment environment;
private BaseResourceNameParser resourceNameParser;
- protected DegradeRuleRegister degradeRuleRegister;
-
- public void setDegradeRuleRegister(DegradeRuleRegister degradeRuleRegister) {
- this.degradeRuleRegister = degradeRuleRegister;
- }
-
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@@ -53,8 +47,5 @@ public Response intercept(Chain chain) throws IOException {
* @throws IOException IOException
*
*/
- protected Response degradeIntercept(String resourceName, Chain chain) throws RetrofitBlockException, IOException {
- Request request = chain.request();
- return this.degradeRuleRegister.exec(resourceName, () -> chain.proceed(request));
- }
+ protected abstract Response degradeIntercept(String resourceName, Chain chain) throws RetrofitBlockException, IOException;
}
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 bef4491..febad15 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,8 +3,7 @@
import java.lang.annotation.*;
/**
- * 应仅采用异常比例模式来控制熔断,超时导致的报错应在okhttp这一层做
- * @author 陈添明 yukdawn@gmail.com
+ * @author 陈添明
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@@ -12,12 +11,17 @@
public @interface Degrade {
/**
- * 异常比例
+ * RT threshold or exception ratio threshold count.
*/
- float count();
+ double count();
/**
- * 时间窗口size,单位:秒
+ * Degrade recover timeout (in seconds) when degradation occurs.
*/
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
deleted file mode 100644
index 742260c..0000000
--- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeRuleRegister.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.github.lianjiatech.retrofit.spring.boot.degrade;
-
-import java.io.IOException;
-import java.util.List;
-
-import okhttp3.Response;
-
-/**
- * @author yukdawn@gmail.com 2022/4/5 23:14
- */
-public interface DegradeRuleRegister {
-
- /**
- * 批量注册规则
- * @param retrofitDegradeRuleList 规则描述对象集合
- */
- void batchRegister(List retrofitDegradeRuleList);
-
- /**
- * 使用规则代理执行目标方法
- * @param resourceName 资源名称
- * @param func 目标方法
- * @return okhttp响应
- * @throws IOException IOException
- */
- Response exec(String resourceName, DegradeProxyMethod func) throws IOException;
-
- @FunctionalInterface
- interface DegradeProxyMethod{
- R get() throws IOException;
- }
-}
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
new file mode 100644
index 0000000..d33ed4c
--- /dev/null
+++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeStrategy.java
@@ -0,0 +1,17 @@
+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/DegradeType.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeType.java
index fb3900a..0b25069 100644
--- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeType.java
+++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/DegradeType.java
@@ -7,6 +7,4 @@ public enum DegradeType {
SENTINEL,
- RESILIENCE4J;
-
}
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
deleted file mode 100644
index 644517a..0000000
--- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/Resilience4jDegradeRuleRegister.java
+++ /dev/null
@@ -1,89 +0,0 @@
-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 c78ce23..757a4d4 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,9 +7,11 @@ public class RetrofitDegradeRule {
private String resourceName;
- private Float count;
+ private double count;
- private Integer timeWindow;
+ private int timeWindow;
+
+ private DegradeStrategy degradeStrategy;
public String getResourceName() {
return resourceName;
@@ -19,20 +21,27 @@ public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
- public Float getCount() {
+ public double getCount() {
return count;
}
- public void setCount(Float count) {
+ public void setCount(double count) {
this.count = count;
}
- public Integer getTimeWindow() {
+ public int getTimeWindow() {
return timeWindow;
}
- public void setTimeWindow(Integer timeWindow) {
+ public void setTimeWindow(int 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/RetrofitDegradeRuleInitializer.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/RetrofitDegradeRuleInitializer.java
new file mode 100644
index 0000000..84a5798
--- /dev/null
+++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/RetrofitDegradeRuleInitializer.java
@@ -0,0 +1,98 @@
+package com.github.lianjiatech.retrofit.spring.boot.degrade;
+
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.ApplicationListener;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * @author 陈添明
+ */
+public class RetrofitDegradeRuleInitializer implements ApplicationListener {
+
+ private final static Logger logger = LoggerFactory.getLogger(RetrofitDegradeRuleInitializer.class);
+
+ private final DegradeProperty degradeProperty;
+
+
+ private static List LIST = new CopyOnWriteArrayList<>();
+
+ public RetrofitDegradeRuleInitializer(DegradeProperty degradeProperty) {
+ this.degradeProperty = degradeProperty;
+ }
+
+
+ public static void addRetrofitDegradeRule(RetrofitDegradeRule degradeRule) {
+ if (degradeRule == null) {
+ return;
+ }
+ LIST.add(degradeRule);
+ }
+
+
+ /**
+ * Handle an application event.
+ *
+ * @param event the event to respond to
+ */
+ @Override
+ public void onApplicationEvent(ApplicationReadyEvent event) {
+ if (!degradeProperty.isEnable()) {
+ return;
+ }
+
+ DegradeType degradeType = degradeProperty.getDegradeType();
+ switch (degradeType) {
+ case SENTINEL: {
+ try {
+ Class.forName("com.alibaba.csp.sentinel.SphU");
+ List rules = new ArrayList<>();
+
+ for (RetrofitDegradeRule degradeRule : LIST) {
+ DegradeStrategy degradeStrategy = degradeRule.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 = degradeRule.getResourceName();
+ // add degrade rule
+ DegradeRule rule = new DegradeRule()
+ .setGrade(grade)
+ // Max allowed response time
+ .setCount(degradeRule.getCount())
+ // Retry timeout (in second)
+ .setTimeWindow(degradeRule.getTimeWindow());
+ rule.setResource(resourceName);
+ rules.add(rule);
+ }
+ DegradeRuleManager.loadRules(rules);
+
+ } catch (Exception e) {
+ logger.warn("com.alibaba.csp.sentinel not found! No SentinelDegradeInterceptor is set.");
+ }
+ break;
+ }
+ default: {
+ throw new IllegalArgumentException("Not currently supported! degradeType=" + degradeType);
+ }
+
+ }
+ }
+}
diff --git a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeInterceptor.java b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeInterceptor.java
new file mode 100644
index 0000000..8fdf478
--- /dev/null
+++ b/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeInterceptor.java
@@ -0,0 +1,37 @@
+package com.github.lianjiatech.retrofit.spring.boot.degrade;
+
+import com.alibaba.csp.sentinel.*;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import okhttp3.Request;
+import okhttp3.Response;
+
+import java.io.IOException;
+
+/**
+ * @author 陈添明
+ */
+public class SentinelDegradeInterceptor extends BaseDegradeInterceptor {
+
+ /**
+ * 熔断拦截处理
+ *
+ * @param chain 请求执行链
+ * @return 请求响应
+ * @throws RetrofitBlockException 如果触发熔断,抛出RetrofitBlockException异常!
+ */
+ @Override
+ protected Response degradeIntercept(String resourceName, Chain chain) throws RetrofitBlockException, IOException {
+ Request request = chain.request();
+ Entry entry = null;
+ try {
+ entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
+ return chain.proceed(request);
+ } catch (BlockException e) {
+ throw new RetrofitBlockException(e);
+ } finally {
+ if (entry != null) {
+ entry.exit();
+ }
+ }
+ }
+}
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
deleted file mode 100644
index c1935cb..0000000
--- a/src/main/java/com/github/lianjiatech/retrofit/spring/boot/degrade/SentinelDegradeRuleRegister.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.github.lianjiatech.retrofit.spring.boot.degrade;
-
-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;
-import com.alibaba.csp.sentinel.EntryType;
-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 okhttp3.Response;
-import org.springframework.util.CollectionUtils;
-
-/**
- * @author yukdawn@gmail.com 2022/4/5 23:15
- */
-public class SentinelDegradeRuleRegister implements DegradeRuleRegister{
-
- @Override
- public void batchRegister(List retrofitDegradeRuleList) {
- if (CollectionUtils.isEmpty(retrofitDegradeRuleList)){
- return;
- }
- DegradeRuleManager.loadRules(retrofitDegradeRuleList.stream().map(this::convert).collect(Collectors.toList()));
- }
-
- @Override
- public Response exec(String resourceName, DegradeProxyMethod func) throws IOException {
- Entry entry = null;
- try {
- entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.OUT);
- return func.get();
- } catch (BlockException e) {
- throw new RetrofitBlockException(e);
- } finally {
- if (entry != null) {
- entry.exit();
- }
- }
- }
-
- private DegradeRule convert(RetrofitDegradeRule retrofitDegradeRule){
- // add degrade rule
- 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 5bc0a11..f99df58 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,7 +42,6 @@ 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 3b4465b..8af32c7 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
@@ -8,10 +8,7 @@
import java.util.concurrent.CompletableFuture;
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;
import org.junit.Assert;
import org.junit.Before;
@@ -59,9 +56,6 @@ public class RetrofitStarterTest {
@Autowired
private HttpApi3 httpApi3;
- @Autowired
- private HttpApi4 httpApi4;
-
private static final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
@@ -423,32 +417,4 @@ public void testBoolean() {
System.out.println(apiBoolean);
}
- @Test
- public void testDegrade() {
- 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(200)
- .addHeader("Content-Type", "application/text; charset=utf-8")
- .addHeader("Cache-Control", "no-cache")
- .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());
- }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
deleted file mode 100644
index e6b12b8..0000000
--- a/src/test/java/com/github/lianjiatech/retrofit/spring/boot/test/http/HttpApi4.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package com.github.lianjiatech.retrofit.spring.boot.test.http;
-
-import com.github.lianjiatech.retrofit.spring.boot.annotation.RetrofitClient;
-import com.github.lianjiatech.retrofit.spring.boot.degrade.Degrade;
-import com.github.lianjiatech.retrofit.spring.boot.degrade.FallbackFactory;
-import com.github.lianjiatech.retrofit.spring.boot.test.entity.Person;
-import com.github.lianjiatech.retrofit.spring.boot.test.entity.Result;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-import retrofit2.http.GET;
-import retrofit2.http.Query;
-
-/**
- * @author 陈添明
- */
-@RetrofitClient(baseUrl = "${test.baseUrl}", fallbackFactory = HttpApi4.HttpDegradeFallbackFactory.class)
-@Degrade(count = 0.5F)
-public interface HttpApi4 {
-
- /**
- * .
- *
- * @param id .
- * @return .
- */
- @GET("degrade/person")
- Result getPerson(@Query("id") Long id);
-
- @Service
- public class HttpDegradeFallbackFactory implements FallbackFactory {
- Logger log = LoggerFactory.getLogger(HttpDegradeFallbackFactory.class);
- /**
- * Returns an instance of the fallback appropriate for the given cause
- *
- * @param cause fallback cause
- * @return 实现了retrofit接口的实例。an instance that implements the retrofit interface.
- */
- @Override
- public HttpApi4 create(Throwable cause) {
- log.error("触发熔断了! ", cause.getMessage(), cause);
- return id -> {
- Result fallback = new Result<>();
- fallback.setCode(100)
- .setMsg("fallback")
- .setData(new Person());
- return fallback;
- };
- }
- }
-
-}
diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml
index 3115af8..70495cb 100644
--- a/src/test/resources/application.yml
+++ b/src/test/resources/application.yml
@@ -54,7 +54,7 @@ retrofit:
# 是否启用熔断降级
enable: true
# 熔断降级实现方式
- degrade-type: resilience4j
+ degrade-type: sentinel
# 熔断资源名称解析器
resource-name-parser: com.github.lianjiatech.retrofit.spring.boot.degrade.DefaultResourceNameParser
# 全局连接超时时间