动态参数配置
@PostMapping(value = "{reqPath}")
Result orderPushCommon(URI uri, @PathVariable("reqPath")String reqPath,@RequestBody DemoBody param);
配置的URI: https://demo.xx.com
配置的reqPath: /api/demo/test
在实际调用时生成的URL为:https://demo.xx.com//api/demo/test,即路径多了个斜杠/。
初步解决方案:
1、https://demo.xx.com改为https://demo.xx.com/
2、或者 /api/demo/test 改为 api/demo/test
此两种方式选其一即可
feign.Contract.BaseContract#parseAndValidateMetadata
protected MethodMetadata parseAndValidateMetadata(Class> targetType, Method method) {
MethodMetadata data = new MethodMetadata();
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
data.configKey(Feign.configKey(targetType, method));
if(targetType.getInterfaces().length == 1) {
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
processAnnotationOnClass(data, targetType);
for (Annotation methodAnnotation : method.getAnnotations()) {
processAnnotationOnMethod(data, methodAnnotation, method);
}
checkState(data.template().method() != null,
"Method %s not annotated with HTTP method type (ex. GET, POST)",
method.getName());
Class>[] parameterTypes = method.getParameterTypes();
Type[] genericParameterTypes = method.getGenericParameterTypes();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
int count = parameterAnnotations.length;
for (int i = 0; i < count; i++) {
boolean isHttpAnnotation = false;
if (parameterAnnotations[i] != null) {
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
}
if (parameterTypes[i] == URI.class) {
data.urlIndex(i);
} else if (!isHttpAnnotation) {
checkState(data.formParams().isEmpty(),
"Body parameters cannot be used with form parameters.");
checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s", method);
data.bodyIndex(i);
data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
}
}
if (data.headerMapIndex() != null) {
checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()], genericParameterTypes[data.headerMapIndex()]);
}
if (data.queryMapIndex() != null) {
checkMapString("QueryMap", parameterTypes[data.queryMapIndex()], genericParameterTypes[data.queryMapIndex()]);
}
return data;
}
注解在classs上的处理
org.springframework.cloud.netflix.feign.support.SpringMvcContract#processAnnotationOnClass
protected void processAnnotationOnClass(MethodMetadata data, Class> clz) {
if (clz.getInterfaces().length == 0) {
RequestMapping classAnnotation = (RequestMapping)AnnotatedElementUtils.findMergedAnnotation(clz, RequestMapping.class);
if (classAnnotation != null && classAnnotation.value().length > 0) {
String pathValue = Util.emptyToNull(classAnnotation.value()[0]);
pathValue = this.resolve(pathValue);
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().insert(0, pathValue);
}
}
}
注解在method的处理
org.springframework.cloud.netflix.feign.support.SpringMvcContract#processAnnotationOnMethod
protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
if (RequestMapping.class.isInstance(methodAnnotation) || methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {
RequestMapping methodMapping = (RequestMapping)AnnotatedElementUtils.findMergedAnnotation(method, RequestMapping.class);
RequestMethod[] methods = methodMapping.method();
if (methods.length == 0) {
methods = new RequestMethod[]{RequestMethod.GET};
}
this.checkOne(method, methods, "method");
data.template().method(methods[0].name());
this.checkAtMostOne(method, methodMapping.value(), "value");
if (methodMapping.value().length > 0) {
String pathValue = Util.emptyToNull(methodMapping.value()[0]);
if (pathValue != null) {
pathValue = this.resolve(pathValue);
if (!pathValue.startsWith("/") && !data.template().toString().endsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().append(pathValue);
}
}
this.parseProduces(data, method, methodMapping);
this.parseConsumes(data, method, methodMapping);
this.parseHeaders(data, method, methodMapping);
data.indexToExpander(new LinkedHashMap());
}
}
关键实现链路,后面在具体分析
1、创建实例 ReflectiveFeign extends Feign#feign.ReflectiveFeign#newInstance
MapnameToHandler = targetToHandlersByName.apply(target);
2、
feign.ReflectiveFeign.ParseHandlersByName#apply
Listmetadata = contract.parseAndValidatateMetadata(key.type());
MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
3、
feign.Contract.BaseContract#parseAndValidateMetadata