【源码品读】深入了解FeignContract协议解析过程
生活随笔
收集整理的這篇文章主要介紹了
【源码品读】深入了解FeignContract协议解析过程
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
abstract class BaseContract implements Contract {
List<MethodMetadata> parseAndValidatateMetadata(Class<?> var1);
@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",targetType.getSimpleName());checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s",targetType.getSimpleName());if (targetType.getInterfaces().length == 1) {checkState(targetType.getInterfaces()[0].getInterfaces().length == 0,"Only single-level inheritance supported: %s",targetType.getSimpleName());}Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();for (Method method : targetType.getMethods()) {if (method.getDeclaringClass() == Object.class ||(method.getModifiers() & Modifier.STATIC) != 0 ||Util.isDefault(method)) {continue;}MethodMetadata metadata = parseAndValidateMetadata(targetType, method);checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",metadata.configKey());result.put(metadata.configKey(), metadata);}return new ArrayList<>(result.values());
}
public interface List<E> extends Collection<E> {
public static boolean isDefault(Method method) {// Default methods are public non-abstract, non-synthetic, and non-static instance methods// declared in an interface.// method.isDefault() is not sufficient for our usage as it does not check// for synthetic methods. As a result, it picks up overridden methods as well as actual default// methods.final int SYNTHETIC = 0x00001000;return ((method.getModifiers()& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC | SYNTHETIC)) == Modifier.PUBLIC)&& method.getDeclaringClass().isInterface();}
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) {if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);}}return data;
}
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {if (clz.getInterfaces().length == 0) {RequestMapping classAnnotation = findMergedAnnotation(clz,RequestMapping.class);if (classAnnotation != null) {// Prepend path from class annotation if specifiedif (classAnnotation.value().length > 0) {String pathValue = emptyToNull(classAnnotation.value()[0]);pathValue = resolve(pathValue);if (!pathValue.startsWith("/")) {pathValue = "/" + pathValue;}data.template().uri(pathValue);}}}
}
@Override
protected void processAnnotationOnMethod(MethodMetadata data,Annotation methodAnnotation, Method method) {if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {return;}RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);// HTTP MethodRequestMethod[] methods = methodMapping.method();if (methods.length == 0) {methods = new RequestMethod[] { RequestMethod.GET };}checkOne(method, methods, "method");data.template().method(Request.HttpMethod.valueOf(methods[0].name()));// pathcheckAtMostOne(method, methodMapping.value(), "value");if (methodMapping.value().length > 0) {String pathValue = emptyToNull(methodMapping.value()[0]);if (pathValue != null) {pathValue = resolve(pathValue);// Append path from @RequestMapping if value is present on methodif (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) {pathValue = "/" + pathValue;}data.template().uri(pathValue, true);}}// producesparseProduces(data, method, methodMapping);// consumesparseConsumes(data, method, methodMapping);// headersparseHeaders(data, method, methodMapping);data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
}
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
private void checkOne(Method method, Object[] values, String fieldName) {checkState(values != null && values.length == 1,"Method %s can only contain 1 %s field. Found: %s", method.getName(),fieldName, values == null ? null : Arrays.asList(values));
}
private void checkAtMostOne(Method method, Object[] values, String fieldName) {checkState(values != null && (values.length == 0 || values.length == 1),"Method %s can only contain at most 1 %s field. Found: %s",method.getName(), fieldName,values == null ? null : Arrays.asList(values));
}
private String resolve(String value) {if (StringUtils.hasText(value)&& this.resourceLoader instanceof ConfigurableApplicationContext) {return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment().resolvePlaceholders(value);}return value;
}
private void parseProduces(MethodMetadata md, Method method,RequestMapping annotation) {String[] serverProduces = annotation.produces();String clientAccepts = serverProduces.length == 0 ? null: emptyToNull(serverProduces[0]);if (clientAccepts != null) {md.template().header(ACCEPT, clientAccepts);}
}
private void parseConsumes(MethodMetadata md, Method method,RequestMapping annotation) {String[] serverConsumes = annotation.consumes();String clientProduces = serverConsumes.length == 0 ? null: emptyToNull(serverConsumes[0]);if (clientProduces != null) {md.template().header(CONTENT_TYPE, clientProduces);}
}
private void parseHeaders(MethodMetadata md, Method method,RequestMapping annotation) {// TODO: only supports one header value per keyif (annotation.headers() != null && annotation.headers().length > 0) {for (String header : annotation.headers()) {int index = header.indexOf('=');if (!header.contains("!=") && index >= 0) {md.template().header(resolve(header.substring(0, index)),resolve(header.substring(index + 1).trim()));}}}
}
?
總結(jié)
以上是生活随笔為你收集整理的【源码品读】深入了解FeignContract协议解析过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Demo】配置重试和超时策略
- 下一篇: 【技术改造】电商系统用户模块集成Feig