package cn.mb.cloud.common.sentinel.fallback; import cn.mb.cloud.common.core.constant.enums.ErrorCodeConstants; import cn.mb.cloud.common.core.util.ResponseData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; /** * 公共 Sentinel Feign 降级处理的安全替代实现。 * *

依赖版本假定所有泛型返回类型均为 {@link Class}。对于 * {@code Map} 等声明并不成立,其运行时类型为 * {@link ParameterizedType};此前转换失败会以 AssertionError 掩盖原始下游异常。

*/ public class DefaultFeignFallback implements MethodInterceptor { private static final Logger log = LoggerFactory.getLogger(DefaultFeignFallback.class); private final Class targetType; private final String targetName; private final Throwable cause; public DefaultFeignFallback(Class targetType, String targetName, Throwable cause) { this.targetType = targetType; this.targetName = targetName; this.cause = cause; } @Override public Object intercept(Object object, Method method, Object[] arguments, MethodProxy methodProxy) { log.error("FunFeignFallback:[{}.{}] serviceId:[{}] message:[{}]", targetType.getName(), method.getName(), targetName, cause == null ? null : cause.getMessage()); Type declaredReturnType = method.getGenericReturnType(); Class returnType = rawType(declaredReturnType); Object data = defaultValue(returnType); // 仅显式声明返回 ResponseData 的方法可以返回 ResponseData 降级结果。 // 在 Map/List 方法中返回该对象会导致 Feign 代理再次抛出 ClassCastException。 if (ResponseData.class.equals(returnType)) { Type dataType = firstTypeArgument(declaredReturnType); return ResponseData.builder() .code(ErrorCodeConstants.FAIL.getValue()) .msg("系统降级,请稍后再试!") .data(defaultValue(rawType(dataType))) .build(); } return data; } private Type firstTypeArgument(Type type) { if (type instanceof ParameterizedType) { Type[] arguments = ((ParameterizedType) type).getActualTypeArguments(); if (arguments.length > 0) return arguments[0]; } return null; } private Class rawType(Type type) { if (type instanceof Class) return (Class) type; if (type instanceof ParameterizedType) return rawType(((ParameterizedType) type).getRawType()); return Object.class; } private Object defaultValue(Class type) { if (List.class.isAssignableFrom(type)) return new ArrayList(); if (Set.class.isAssignableFrom(type)) return new HashSet(); if (Map.class.isAssignableFrom(type)) return new HashMap(); if (Boolean.class.equals(type) || boolean.class.equals(type)) return Boolean.FALSE; if (type.isPrimitive()) return primitiveDefault(type); return null; } private Object primitiveDefault(Class type) { if (char.class.equals(type)) return Character.valueOf('\0'); if (byte.class.equals(type)) return Byte.valueOf((byte) 0); if (short.class.equals(type)) return Short.valueOf((short) 0); if (int.class.equals(type)) return Integer.valueOf(0); if (long.class.equals(type)) return Long.valueOf(0L); if (float.class.equals(type)) return Float.valueOf(0F); if (double.class.equals(type)) return Double.valueOf(0D); return null; } }