mirror of
https://gitee.com/log4j/pig.git
synced 2024-12-23 05:00:23 +08:00
✨ close #I6B5EU common-feign 支持接口级别重试
This commit is contained in:
parent
917ee2a636
commit
161d3a57f1
@ -16,52 +16,57 @@
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</parent>
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common</artifactId>
|
||||
<version>3.6.5</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>pig-common-feign</artifactId>
|
||||
<description>feign-sentinel服务降级熔断、限流组件</description>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>pig-common-feign</artifactId>
|
||||
<description>feign-sentinel服务降级熔断、限流组件</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
<!--feign 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<!-- okhttp 扩展 -->
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
</dependency>
|
||||
<!-- LB 扩展 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<!--caffeine 替换LB 默认缓存实现-->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
<!--oauth server 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
<!--feign 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
<!-- okhttp 扩展 -->
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
</dependency>
|
||||
<!-- LB 扩展 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<!--caffeine 替换LB 默认缓存实现-->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
</dependency>
|
||||
<!--oauth server 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<!--重试-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -20,6 +20,7 @@ import com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration;
|
||||
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
|
||||
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.pig4cloud.pig.common.feign.retry.FeignRetryAspect;
|
||||
import com.pig4cloud.pig.common.feign.sentinel.ext.PigSentinelFeign;
|
||||
import com.pig4cloud.pig.common.feign.sentinel.handle.PigUrlBlockHandler;
|
||||
import com.pig4cloud.pig.common.feign.sentinel.parser.PigHeaderRequestOriginParser;
|
||||
@ -61,4 +62,9 @@ public class PigFeignAutoConfiguration {
|
||||
return new PigHeaderRequestOriginParser();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FeignRetryAspect feignRetryAspect() {
|
||||
return new FeignRetryAspect();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
package com.pig4cloud.pig.common.feign.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 重试具体的策略
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Backoff {
|
||||
|
||||
long delay() default 1000L;;
|
||||
|
||||
long maxDelay() default 0L;
|
||||
|
||||
double multiplier() default 0.0D;;
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.pig4cloud.pig.common.feign.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 重试注解,作用在 @FeignClient 注解之上
|
||||
*/
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface FeignRetry {
|
||||
|
||||
Backoff backoff() default @Backoff();
|
||||
|
||||
int maxAttempt() default 3;
|
||||
|
||||
Class<? extends Throwable>[] include() default {};
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package com.pig4cloud.pig.common.feign.retry;
|
||||
|
||||
import com.pig4cloud.pig.common.feign.annotation.FeignRetry;
|
||||
import feign.RetryableException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.retry.backoff.BackOffPolicy;
|
||||
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
|
||||
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* FeignRetry 注解切面注入 retryTemplate
|
||||
*
|
||||
* @author lengleng
|
||||
* @date 2023/1/21
|
||||
* {@link org.springframework.cloud.loadbalancer.blocking.retry.BlockingLoadBalancedRetryPolicy}.
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class FeignRetryAspect {
|
||||
|
||||
@Around("@annotation(feignRetry)")
|
||||
public Object retry(ProceedingJoinPoint joinPoint, FeignRetry feignRetry) throws Throwable {
|
||||
Method method = getCurrentMethod(joinPoint);
|
||||
|
||||
RetryTemplate retryTemplate = new RetryTemplate();
|
||||
retryTemplate.setBackOffPolicy(prepareBackOffPolicy(feignRetry));
|
||||
retryTemplate.setRetryPolicy(prepareSimpleRetryPolicy(feignRetry));
|
||||
|
||||
// 重试
|
||||
return retryTemplate.execute(arg0 -> {
|
||||
int retryCount = arg0.getRetryCount();
|
||||
log.info("Sending request method: {}, max attempt: {}, delay: {}, retryCount: {}", method.getName(),
|
||||
feignRetry.maxAttempt(), feignRetry.backoff().delay(), retryCount);
|
||||
return joinPoint.proceed(joinPoint.getArgs());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造重试策略
|
||||
* @param feignRetry 重试注解
|
||||
* @return BackOffPolicy
|
||||
*/
|
||||
private BackOffPolicy prepareBackOffPolicy(FeignRetry feignRetry) {
|
||||
if (feignRetry.backoff().multiplier() != 0) {
|
||||
ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
|
||||
backOffPolicy.setInitialInterval(feignRetry.backoff().delay());
|
||||
backOffPolicy.setMaxInterval(feignRetry.backoff().maxDelay());
|
||||
backOffPolicy.setMultiplier(feignRetry.backoff().multiplier());
|
||||
return backOffPolicy;
|
||||
}
|
||||
else {
|
||||
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
|
||||
fixedBackOffPolicy.setBackOffPeriod(feignRetry.backoff().delay());
|
||||
return fixedBackOffPolicy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造重试策略
|
||||
* @param feignRetry 重试注解
|
||||
* @return SimpleRetryPolicy
|
||||
*/
|
||||
private SimpleRetryPolicy prepareSimpleRetryPolicy(FeignRetry feignRetry) {
|
||||
Map<Class<? extends Throwable>, Boolean> policyMap = new HashMap<>();
|
||||
policyMap.put(RetryableException.class, true); // Connection refused or time out
|
||||
|
||||
if (feignRetry.include().length != 0) {
|
||||
for (Class<? extends Throwable> t : feignRetry.include()) {
|
||||
policyMap.put(t, true);
|
||||
}
|
||||
}
|
||||
|
||||
return new SimpleRetryPolicy(feignRetry.maxAttempt(), policyMap, true);
|
||||
}
|
||||
|
||||
private Method getCurrentMethod(JoinPoint joinPoint) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
return signature.getMethod();
|
||||
}
|
||||
|
||||
}
|
@ -25,12 +25,14 @@ import com.alibaba.csp.sentinel.Tracer;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.pig4cloud.pig.common.core.util.R;
|
||||
import com.pig4cloud.pig.common.feign.annotation.FeignRetry;
|
||||
import feign.Feign;
|
||||
import feign.InvocationHandlerFactory;
|
||||
import feign.MethodMetadata;
|
||||
import feign.Target;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -38,6 +40,7 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import static feign.Util.checkNotNull;
|
||||
|
||||
@ -134,8 +137,9 @@ public class PigSentinelInvocationHandler implements InvocationHandler {
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 若是R类型 执行自动降级返回R
|
||||
if (R.class == method.getReturnType()) {
|
||||
// 若是R类型 并且不包含@FeignRetry 执行自动降级返回R
|
||||
FeignRetry feignRetry = AnnotationUtils.findAnnotation(method, FeignRetry.class);
|
||||
if (R.class == method.getReturnType() && Objects.isNull(feignRetry)) {
|
||||
log.error("feign 服务间调用异常", ex);
|
||||
return R.failed(ex.getLocalizedMessage());
|
||||
}
|
||||
|
@ -43,8 +43,8 @@
|
||||
</dependency>
|
||||
<!--feign 注解依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pig-common-feign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--mybatis 依赖-->
|
||||
|
Loading…
Reference in New Issue
Block a user