feat:2.3.0
1. 修复AOP扫描的Object里面的方法,导致获取不到Retryable报错问题
This commit is contained in:
parent
408a0f2699
commit
631a59b91c
@ -1,10 +1,15 @@
|
|||||||
package com.aizuda.easy.retry.client.core.intercepter;
|
package com.aizuda.easy.retry.client.core.intercepter;
|
||||||
|
|
||||||
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.aizuda.easy.retry.client.core.annotation.Retryable;
|
import com.aizuda.easy.retry.client.core.annotation.Retryable;
|
||||||
import com.aizuda.easy.retry.client.core.cache.GroupVersionCache;
|
import com.aizuda.easy.retry.client.core.cache.GroupVersionCache;
|
||||||
|
import com.aizuda.easy.retry.client.core.cache.RetryerInfoCache;
|
||||||
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
|
import com.aizuda.easy.retry.client.core.config.EasyRetryProperties;
|
||||||
|
import com.aizuda.easy.retry.client.core.exception.EasyRetryClientException;
|
||||||
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot.EnumStage;
|
import com.aizuda.easy.retry.client.core.intercepter.RetrySiteSnapshot.EnumStage;
|
||||||
|
import com.aizuda.easy.retry.client.core.retryer.RetryerInfo;
|
||||||
import com.aizuda.easy.retry.client.core.retryer.RetryerResultContext;
|
import com.aizuda.easy.retry.client.core.retryer.RetryerResultContext;
|
||||||
import com.aizuda.easy.retry.client.core.strategy.RetryStrategy;
|
import com.aizuda.easy.retry.client.core.strategy.RetryStrategy;
|
||||||
import com.aizuda.easy.retry.common.core.alarm.Alarm;
|
import com.aizuda.easy.retry.common.core.alarm.Alarm;
|
||||||
@ -13,12 +18,14 @@ import com.aizuda.easy.retry.common.core.alarm.EasyRetryAlarmFactory;
|
|||||||
import com.aizuda.easy.retry.common.core.enums.NotifySceneEnum;
|
import com.aizuda.easy.retry.common.core.enums.NotifySceneEnum;
|
||||||
import com.aizuda.easy.retry.common.core.enums.RetryResultStatusEnum;
|
import com.aizuda.easy.retry.common.core.enums.RetryResultStatusEnum;
|
||||||
import com.aizuda.easy.retry.common.core.log.LogUtils;
|
import com.aizuda.easy.retry.common.core.log.LogUtils;
|
||||||
|
import com.aizuda.easy.retry.common.core.model.EasyRetryHeaders;
|
||||||
import com.aizuda.easy.retry.common.core.util.EnvironmentUtils;
|
import com.aizuda.easy.retry.common.core.util.EnvironmentUtils;
|
||||||
import com.aizuda.easy.retry.server.model.dto.ConfigDTO;
|
import com.aizuda.easy.retry.server.model.dto.ConfigDTO;
|
||||||
import com.google.common.base.Defaults;
|
import com.google.common.base.Defaults;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.aopalliance.intercept.MethodInterceptor;
|
import org.aopalliance.intercept.MethodInterceptor;
|
||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
import org.springframework.aop.AfterAdvice;
|
import org.springframework.aop.AfterAdvice;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
@ -26,12 +33,14 @@ import org.springframework.core.Ordered;
|
|||||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.core.env.StandardEnvironment;
|
import org.springframework.core.env.StandardEnvironment;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,6 +129,8 @@ public class EasyRetryInterceptor implements MethodInterceptor, AfterAdvice, Ser
|
|||||||
|| RetrySiteSnapshot.isRetryFlow()
|
|| RetrySiteSnapshot.isRetryFlow()
|
||||||
// 下游响应不重试码,不开启重试
|
// 下游响应不重试码,不开启重试
|
||||||
|| RetrySiteSnapshot.isRetryForStatusCode()
|
|| RetrySiteSnapshot.isRetryForStatusCode()
|
||||||
|
// 匹配异常信息
|
||||||
|
|| !validate(throwable, RetryerInfoCache.get(retryable.scene(), executorClassName))
|
||||||
) {
|
) {
|
||||||
if (!RetrySiteSnapshot.isMethodEntrance(methodEntrance)) {
|
if (!RetrySiteSnapshot.isMethodEntrance(methodEntrance)) {
|
||||||
LogUtils.debug(log, "Non-method entry does not enable local retries. traceId:[{}] [{}]", traceId, RetrySiteSnapshot.getMethodEntrance());
|
LogUtils.debug(log, "Non-method entry does not enable local retries. traceId:[{}] [{}]", traceId, RetrySiteSnapshot.getMethodEntrance());
|
||||||
@ -131,6 +142,8 @@ public class EasyRetryInterceptor implements MethodInterceptor, AfterAdvice, Ser
|
|||||||
LogUtils.debug(log, "Retry traffic does not enable local retries. traceId:[{}] [{}]", traceId, RetrySiteSnapshot.getRetryHeader());
|
LogUtils.debug(log, "Retry traffic does not enable local retries. traceId:[{}] [{}]", traceId, RetrySiteSnapshot.getRetryHeader());
|
||||||
} else if (RetrySiteSnapshot.isRetryForStatusCode()) {
|
} else if (RetrySiteSnapshot.isRetryForStatusCode()) {
|
||||||
LogUtils.debug(log, "Existing exception retry codes do not enable local retries. traceId:[{}]", traceId);
|
LogUtils.debug(log, "Existing exception retry codes do not enable local retries. traceId:[{}]", traceId);
|
||||||
|
} else if(!validate(throwable, RetryerInfoCache.get(retryable.scene(), executorClassName))) {
|
||||||
|
LogUtils.debug(log, "Exception mismatch. traceId:[{}]", traceId);
|
||||||
} else {
|
} else {
|
||||||
LogUtils.debug(log, "Unknown situations do not enable local retry scenarios. traceId:[{}]", traceId);
|
LogUtils.debug(log, "Unknown situations do not enable local retry scenarios. traceId:[{}]", traceId);
|
||||||
}
|
}
|
||||||
@ -144,10 +157,14 @@ public class EasyRetryInterceptor implements MethodInterceptor, AfterAdvice, Ser
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// 标识重试流量
|
||||||
|
initHeaders(retryable);
|
||||||
|
|
||||||
RetryerResultContext context = retryStrategy.openRetry(retryable.scene(), executorClassName, point.getArguments());
|
RetryerResultContext context = retryStrategy.openRetry(retryable.scene(), executorClassName, point.getArguments());
|
||||||
LogUtils.info(log,"local retry result. traceId:[{}] message:[{}]", traceId, context);
|
|
||||||
if (RetryResultStatusEnum.SUCCESS.getStatus().equals(context.getRetryResultStatusEnum().getStatus())) {
|
if (RetryResultStatusEnum.SUCCESS.getStatus().equals(context.getRetryResultStatusEnum().getStatus())) {
|
||||||
LogUtils.debug(log, "local retry successful. traceId:[{}] result:[{}]", traceId, context.getResult());
|
LogUtils.debug(log, "local retry successful. traceId:[{}] result:[{}]", traceId, context.getResult());
|
||||||
|
} else {
|
||||||
|
LogUtils.info(log,"local retry result. traceId:[{}] throwable:[{}]", traceId, context.getThrowable());
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
@ -164,6 +181,15 @@ public class EasyRetryInterceptor implements MethodInterceptor, AfterAdvice, Ser
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initHeaders(final Retryable retryable) {
|
||||||
|
|
||||||
|
EasyRetryHeaders easyRetryHeaders = new EasyRetryHeaders();
|
||||||
|
easyRetryHeaders.setEasyRetry(Boolean.TRUE);
|
||||||
|
easyRetryHeaders.setEasyRetryId(IdUtil.getSnowflakeNextIdStr());
|
||||||
|
easyRetryHeaders.setDdl(GroupVersionCache.getDdl(retryable.scene()));
|
||||||
|
RetrySiteSnapshot.setRetryHeader(easyRetryHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
private void sendMessage(Exception e) {
|
private void sendMessage(Exception e) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -205,13 +231,10 @@ public class EasyRetryInterceptor implements MethodInterceptor, AfterAdvice, Ser
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (retryable == null) {
|
if (retryable == null) {
|
||||||
//返回当前类或父类或接口方法上标注的注解对象
|
// 返回当前类或父类或接口方法上标注的注解对象
|
||||||
retryable = AnnotatedElementUtils.findMergedAnnotation(method, Retryable.class);
|
retryable = AnnotatedElementUtils.findMergedAnnotation(method, Retryable.class);
|
||||||
}
|
}
|
||||||
if (retryable == null) {
|
|
||||||
//返回当前类或父类或接口上标注的注解对象
|
|
||||||
retryable = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), Retryable.class);
|
|
||||||
}
|
|
||||||
return retryable;
|
return retryable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,4 +245,33 @@ public class EasyRetryInterceptor implements MethodInterceptor, AfterAdvice, Ser
|
|||||||
return Integer.parseInt(order);
|
return Integer.parseInt(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private boolean validate(Throwable throwable, RetryerInfo retryerInfo) {
|
||||||
|
|
||||||
|
Set<Class<? extends Throwable>> exclude = retryerInfo.getExclude();
|
||||||
|
Set<Class<? extends Throwable>> include = retryerInfo.getInclude();
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(include) && CollectionUtils.isEmpty(exclude)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Class<? extends Throwable> e : include) {
|
||||||
|
if (e.isAssignableFrom(throwable.getClass())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(exclude)) {
|
||||||
|
for (Class<? extends Throwable> e : exclude) {
|
||||||
|
if (e.isAssignableFrom(throwable.getClass())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package com.aizuda.easy.retry.client.core.intercepter;
|
package com.aizuda.easy.retry.client.core.intercepter;
|
||||||
|
|
||||||
import com.aizuda.easy.retry.client.core.annotation.Retryable;
|
import com.aizuda.easy.retry.client.core.annotation.Retryable;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.aopalliance.aop.Advice;
|
import org.aopalliance.aop.Advice;
|
||||||
import org.springframework.aop.ClassFilter;
|
import org.springframework.aop.ClassFilter;
|
||||||
import org.springframework.aop.IntroductionAdvisor;
|
import org.springframework.aop.IntroductionAdvisor;
|
||||||
import org.springframework.aop.MethodMatcher;
|
import org.springframework.aop.MethodMatcher;
|
||||||
import org.springframework.aop.Pointcut;
|
import org.springframework.aop.Pointcut;
|
||||||
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
import org.springframework.aop.support.AbstractPointcutAdvisor;
|
||||||
import org.springframework.aop.support.ComposablePointcut;
|
|
||||||
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
import org.springframework.aop.support.StaticMethodMatcherPointcut;
|
||||||
import org.springframework.aop.support.annotation.AnnotationClassFilter;
|
import org.springframework.aop.support.annotation.AnnotationClassFilter;
|
||||||
import org.springframework.aop.support.annotation.AnnotationMethodMatcher;
|
import org.springframework.aop.support.annotation.AnnotationMethodMatcher;
|
||||||
@ -15,23 +15,21 @@ import org.springframework.beans.factory.BeanFactory;
|
|||||||
import org.springframework.beans.factory.BeanFactoryAware;
|
import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.ReflectionUtils.MethodCallback;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author www.byteblogs.com
|
* @author www.byteblogs.com
|
||||||
* @date 2023-08-23
|
* @date 2023-08-23
|
||||||
*/
|
*/
|
||||||
@Component
|
@Configuration
|
||||||
|
@Slf4j
|
||||||
public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements IntroductionAdvisor, BeanFactoryAware, InitializingBean {
|
public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements IntroductionAdvisor, BeanFactoryAware, InitializingBean {
|
||||||
private Advice advice;
|
private Advice advice;
|
||||||
private Pointcut pointcut;
|
private Pointcut pointcut;
|
||||||
@ -41,9 +39,7 @@ public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
Set<Class<? extends Annotation>> retryableAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>(1);
|
this.pointcut = buildPointcut();
|
||||||
retryableAnnotationTypes.add(Retryable.class);
|
|
||||||
this.pointcut = buildPointcut(retryableAnnotationTypes);
|
|
||||||
this.advice = buildAdvice();
|
this.advice = buildAdvice();
|
||||||
if (this.advice instanceof BeanFactoryAware) {
|
if (this.advice instanceof BeanFactoryAware) {
|
||||||
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
|
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
|
||||||
@ -81,23 +77,8 @@ public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements
|
|||||||
return easyRetryInterceptor;
|
return easyRetryInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected Pointcut buildPointcut() {
|
||||||
* Calculate a pointcut for the given retry annotation types, if any.
|
return new AnnotationClassOrMethodPointcut(Retryable.class);
|
||||||
* @param retryAnnotationTypes the retry annotation types to introspect
|
|
||||||
* @return the applicable Pointcut object, or {@code null} if none
|
|
||||||
*/
|
|
||||||
protected Pointcut buildPointcut(Set<Class<? extends Annotation>> retryAnnotationTypes) {
|
|
||||||
ComposablePointcut result = null;
|
|
||||||
for (Class<? extends Annotation> retryAnnotationType : retryAnnotationTypes) {
|
|
||||||
Pointcut filter = new AnnotationClassOrMethodPointcut(retryAnnotationType);
|
|
||||||
if (result == null) {
|
|
||||||
result = new ComposablePointcut(filter);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result.union(filter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -110,13 +91,13 @@ public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements
|
|||||||
private final MethodMatcher methodResolver;
|
private final MethodMatcher methodResolver;
|
||||||
|
|
||||||
AnnotationClassOrMethodPointcut(Class<? extends Annotation> annotationType) {
|
AnnotationClassOrMethodPointcut(Class<? extends Annotation> annotationType) {
|
||||||
this.methodResolver = new AnnotationMethodMatcher(annotationType);
|
this.methodResolver = new AnnotationMethodMatcher(annotationType, true);
|
||||||
setClassFilter(new AnnotationClassOrMethodFilter(annotationType));
|
setClassFilter(new AnnotationClassOrMethodFilter(annotationType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(Method method, Class<?> targetClass) {
|
public boolean matches(Method method, Class<?> targetClass) {
|
||||||
return getClassFilter().matches(targetClass) || this.methodResolver.matches(method, targetClass);
|
return this.methodResolver.matches(method, targetClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -133,7 +114,8 @@ public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class AnnotationClassOrMethodFilter extends AnnotationClassFilter {
|
|
||||||
|
private static final class AnnotationClassOrMethodFilter extends AnnotationClassFilter {
|
||||||
|
|
||||||
private final AnnotationMethodsResolver methodResolver;
|
private final AnnotationMethodsResolver methodResolver;
|
||||||
|
|
||||||
@ -159,16 +141,13 @@ public class EasyRetryPointcutAdvisor extends AbstractPointcutAdvisor implements
|
|||||||
|
|
||||||
public boolean hasAnnotatedMethods(Class<?> clazz) {
|
public boolean hasAnnotatedMethods(Class<?> clazz) {
|
||||||
final AtomicBoolean found = new AtomicBoolean(false);
|
final AtomicBoolean found = new AtomicBoolean(false);
|
||||||
ReflectionUtils.doWithMethods(clazz, new MethodCallback() {
|
ReflectionUtils.doWithMethods(clazz, method -> {
|
||||||
@Override
|
if (found.get()) {
|
||||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
return;
|
||||||
if (found.get()) {
|
}
|
||||||
return;
|
Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
|
||||||
}
|
if (annotation != null) {
|
||||||
Annotation annotation = AnnotationUtils.findAnnotation(method, annotationType);
|
found.set(true);
|
||||||
if (annotation != null) {
|
|
||||||
found.set(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return found.get();
|
return found.get();
|
||||||
|
Loading…
Reference in New Issue
Block a user