Skip to content

Commit

Permalink
Merge pull request LianjiaTech#105 from DawnSouther/master
Browse files Browse the repository at this point in the history
熔断限流组件优化集成逻辑
  • Loading branch information
chentianming11 authored Apr 17, 2022
2 parents 95f340d + 14fd4d2 commit f804b10
Show file tree
Hide file tree
Showing 18 changed files with 404 additions and 250 deletions.
9 changes: 9 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
<okio.version>1.17.5</okio.version>
<sentinel.version>1.6.3</sentinel.version>
<jackson.version>2.12.6.1</jackson.version>
<resilience4j-spring.version>1.7.1</resilience4j-spring.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -159,6 +160,14 @@
<version>${sentinel.version}</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.github.resilience4j/resilience4j-spring -->
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>${resilience4j-spring.version}</version>
<scope>provided</scope>
</dependency>

</dependencies>

<distributionManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,23 @@
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;
Expand All @@ -29,7 +38,6 @@
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;
Expand Down Expand Up @@ -71,7 +79,7 @@ public GlobalAndNetworkInterceptorFinder globalAndNetworkInterceptorFinder() {

@Bean
@ConditionalOnMissingBean
public RetrofitConfigBean retrofitConfigBean() throws IllegalAccessException, InstantiationException {
public RetrofitConfigBean retrofitConfigBean(ObjectProvider<DegradeRuleRegister> degradeRuleRegisterObjectProvider) throws IllegalAccessException, InstantiationException {
RetrofitConfigBean retrofitConfigBean =
new RetrofitConfigBean(retrofitProperties, globalAndNetworkInterceptorFinder());
// Initialize the connection pool
Expand Down Expand Up @@ -121,9 +129,28 @@ public RetrofitConfigBean retrofitConfigBean() throws IllegalAccessException, In
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
Expand All @@ -145,11 +172,6 @@ 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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;
Expand Down Expand Up @@ -37,6 +38,8 @@ public class RetrofitConfigBean {

private BaseResourceNameParser resourceNameParser;

private DegradeRuleRegister degradeRuleRegister;

public RetrofitProperties getRetrofitProperties() {
return retrofitProperties;
}
Expand Down Expand Up @@ -105,4 +108,12 @@ public BaseResourceNameParser getResourceNameParser() {
public void setResourceNameParser(BaseResourceNameParser resourceNameParser) {
this.resourceNameParser = resourceNameParser;
}

public DegradeRuleRegister getDegradeRuleRegister() {
return degradeRuleRegister;
}

public void setDegradeRuleRegister(DegradeRuleRegister degradeRuleRegister) {
this.degradeRuleRegister = degradeRuleRegister;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
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.*;
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;
Expand All @@ -36,14 +33,6 @@
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;
Expand Down Expand Up @@ -73,7 +62,7 @@ public class RetrofitFactoryBean<T> implements FactoryBean<T>, EnvironmentAware,
private static final Map<Class<? extends CallAdapter.Factory>, CallAdapter.Factory> CALL_ADAPTER_FACTORIES_CACHE =
new HashMap<>(4);

private Class<T> retrofitInterface;
private final Class<T> retrofitInterface;

private Environment environment;

Expand All @@ -83,7 +72,7 @@ public class RetrofitFactoryBean<T> implements FactoryBean<T>, EnvironmentAware,

private ApplicationContext applicationContext;

private RetrofitClient retrofitClient;
private final RetrofitClient retrofitClient;

private static final Map<Class<? extends Converter.Factory>, Converter.Factory> CONVERTER_FACTORIES_CACHE =
new HashMap<>(4);
Expand Down Expand Up @@ -122,40 +111,52 @@ public T getObject() throws Exception {
);
}

/**
* 加载熔断配置,熔断粒度可控制到方法级别
*/
private void loadDegradeRules() {
// 读取熔断配置
Method[] methods = retrofitInterface.getMethods();
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);
}

if (degrade == null) {
continue;
}
DegradeProperty degradeProperty = retrofitProperties.getDegrade();
DegradeRuleRegister degradeRuleRegister = retrofitConfigBean.getDegradeRuleRegister();

DegradeStrategy degradeStrategy = degrade.degradeStrategy();
BaseResourceNameParser resourceNameParser = retrofitConfigBean.getResourceNameParser();
String resourceName = resourceNameParser.parseResourceName(method, environment);
if (!degradeProperty.isEnable()) {
return;
}
Assert.notNull(degradeRuleRegister, "[DegradeRuleRegister] not found bean instance");
Method[] methods = retrofitInterface.getMethods();
List<RetrofitDegradeRule> retrofitDegradeRuleList = Arrays.stream(methods)
.map(this::convertSentinelRule)
.filter(Objects::nonNull)
.collect(Collectors.toList());
degradeRuleRegister.batchRegister(retrofitDegradeRuleList);
}

RetrofitDegradeRule degradeRule = new RetrofitDegradeRule();
degradeRule.setCount(degrade.count());
degradeRule.setDegradeStrategy(degradeStrategy);
degradeRule.setTimeWindow(degrade.timeWindow());
degradeRule.setResourceName(resourceName);
RetrofitDegradeRuleInitializer.addRetrofitDegradeRule(degradeRule);
/**
* 提取熔断规则,优先级为方法>类>默认
* @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);
}
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;
}

/**
Expand Down Expand Up @@ -277,26 +278,14 @@ private synchronized OkHttpClient getOkHttpClient(Class<?> retrofitClientInterfa
}

// add DegradeInterceptor
// 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");
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);
}
}
DegradeInterceptor degradeInterceptor = new DegradeInterceptor();
degradeInterceptor.setEnvironment(environment);
degradeInterceptor.setResourceNameParser(retrofitConfigBean.getResourceNameParser());
degradeInterceptor.setDegradeRuleRegister(retrofitConfigBean.getDegradeRuleRegister());
okHttpClientBuilder.addInterceptor(degradeInterceptor);
}

// add ServiceInstanceChooserInterceptor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,21 @@
import java.lang.annotation.*;

/**
* @author 陈添明
* 应仅采用异常比例模式来控制熔断,超时导致的报错应在okhttp这一层做
* @author 陈添明 [email protected]
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@
/**
* @author 陈添明
*/
public abstract class BaseDegradeInterceptor implements Interceptor {
public class DegradeInterceptor 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;
}
Expand Down Expand Up @@ -47,5 +53,8 @@ public Response intercept(Chain chain) throws IOException {
* @throws IOException IOException
*
*/
protected abstract Response degradeIntercept(String resourceName, Chain chain) throws RetrofitBlockException, IOException;
protected Response degradeIntercept(String resourceName, Chain chain) throws RetrofitBlockException, IOException {
Request request = chain.request();
return this.degradeRuleRegister.exec(resourceName, () -> chain.proceed(request));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.github.lianjiatech.retrofit.spring.boot.degrade;

import java.io.IOException;
import java.util.List;

import okhttp3.Response;

/**
* @author [email protected] 2022/4/5 23:14
*/
public interface DegradeRuleRegister {

/**
* 批量注册规则
* @param retrofitDegradeRuleList 规则描述对象集合
*/
void batchRegister(List<RetrofitDegradeRule> retrofitDegradeRuleList);

/**
* 使用规则代理执行目标方法
* @param resourceName 资源名称
* @param func 目标方法
* @return okhttp响应
* @throws IOException IOException
*/
Response exec(String resourceName, DegradeProxyMethod<Response> func) throws IOException;

@FunctionalInterface
interface DegradeProxyMethod<R>{
R get() throws IOException;
}
}
Loading

0 comments on commit f804b10

Please sign in to comment.