From 6aaa9b8cbecffc292303c2a0e686c5053205370b Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Tue, 31 Jan 2023 19:04:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8D=87=E7=BA=A71.0.7=EF=BC=8C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E6=89=A7=E8=A1=8C=E5=99=A8=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=96=B9=E6=B3=95=E7=BC=93=E5=AD=98?= =?UTF-8?q?=EF=BC=8C=E6=8F=90=E9=AB=98=E5=B9=B6=E5=8F=91=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 +- rest-proxy-api/pom.xml | 2 +- rest-proxy-core/pom.xml | 2 +- .../rest/registry/proxy/RestProxyInvoker.java | 79 ++++++------ .../registry/proxy/entity/RestMethod.java | 117 ++++++++++++++++++ .../proxy/support/ArgumentResolveContext.java | 6 +- .../RestArgumentResolverComposite.java | 12 +- .../resolvers/RestParamArgumentResolver.java | 2 +- 8 files changed, 172 insertions(+), 52 deletions(-) create mode 100644 rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/entity/RestMethod.java diff --git a/pom.xml b/pom.xml index 9201fe2..45b7f4b 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ group.flyfish rest-proxy - 1.0.6 + 1.0.7 8 @@ -22,7 +22,7 @@ 1.8 4.4 2.6 - 1.0.6 + 1.0.7 pom diff --git a/rest-proxy-api/pom.xml b/rest-proxy-api/pom.xml index d8f176e..27a8d42 100644 --- a/rest-proxy-api/pom.xml +++ b/rest-proxy-api/pom.xml @@ -5,7 +5,7 @@ group.flyfish rest-proxy - 1.0.6 + 1.0.7 4.0.0 diff --git a/rest-proxy-core/pom.xml b/rest-proxy-core/pom.xml index 0c06d33..a94c3bf 100644 --- a/rest-proxy-core/pom.xml +++ b/rest-proxy-core/pom.xml @@ -5,7 +5,7 @@ group.flyfish rest-proxy - 1.0.6 + 1.0.7 4.0.0 diff --git a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/RestProxyInvoker.java b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/RestProxyInvoker.java index 01ebb09..35b0901 100644 --- a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/RestProxyInvoker.java +++ b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/RestProxyInvoker.java @@ -2,7 +2,6 @@ package group.flyfish.rest.registry.proxy; import com.fasterxml.jackson.databind.JavaType; import group.flyfish.rest.annotation.AutoMapping; -import group.flyfish.rest.annotation.RestApi; import group.flyfish.rest.annotation.RestService; import group.flyfish.rest.configuration.RestClientProperties; import group.flyfish.rest.configuration.configure.PropertiesConfigurable; @@ -11,12 +10,14 @@ import group.flyfish.rest.core.client.RestClient; import group.flyfish.rest.core.client.RestClientBuilder; import group.flyfish.rest.mapping.RestResultMapping; import group.flyfish.rest.registry.RestApiRegistry; +import group.flyfish.rest.registry.proxy.entity.RestMethod; import group.flyfish.rest.registry.proxy.support.ArgumentResolveContext; import group.flyfish.rest.registry.proxy.support.RestArgumentResolverComposite; import group.flyfish.rest.registry.proxy.support.UrlCompiler; import group.flyfish.rest.registry.wrapper.DefaultRestResultMapping; import group.flyfish.rest.utils.DataUtils; import group.flyfish.rest.utils.JacksonUtil; +import lombok.Getter; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.http.client.config.RequestConfig; @@ -25,14 +26,13 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import java.beans.Transient; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.util.Map; -import java.util.stream.Stream; +import java.util.concurrent.ConcurrentHashMap; /** * Rest代理执行器 @@ -42,13 +42,17 @@ import java.util.stream.Stream; @Slf4j public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurable { + // 方法缓存 + private final Map methods = new ConcurrentHashMap<>(); // 要代理的目标类 private final Class targetType; // 服务映射 private final RestService restService; // 配置属性 + @Getter private RestClientProperties properties; // 初始的基本路径 + @Getter private String baseUrl; // 超时时间 private RequestConfig config; @@ -59,6 +63,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab // 鉴权提供者 private RestAuthProvider authProvider; + /** * 构造器 * @@ -103,34 +108,27 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab * 执行rest请求的地方,这里很简单易懂 * * @param proxy 代理对象 - * @param method 代理方法 + * @param target 代理方法 * @param args 参数 * @return 结果 * @throws Throwable 可能抛出的异常 */ @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - // 处理基本方法被代理的情况 - if (AopUtils.isEqualsMethod(method)) { - Object obj = args[0]; - // The target does not implement the equals(Object) method itself. - return null != obj && ClassUtils.isAssignable(targetType, obj.getClass()); - } else if (AopUtils.isHashCodeMethod(method)) { - // The target does not implement the hashCode() method itself. - return -1; - } - // 无视proxy,因为啥也没 - RestApi restApi = AnnotationUtils.findAnnotation(method, RestApi.class); - if (null == restApi) { + public Object invoke(Object proxy, Method target, Object[] args) throws Throwable { + // 解析方法,做基本验证 + RestMethod method = methods.computeIfAbsent(target.hashCode(), k -> RestMethod.resolve(target, this)); + if (method.isInvalid()) { throw new IllegalAccessException("【Rest调用】未声明rest配置的方法被调用!请检查代码!"); } RestArgumentResolverComposite composite = registry.getComposite(); // 第一步就解析参数 - ArgumentResolveContext context = composite.resolve(restApi, method, args); + ArgumentResolveContext context = composite.resolve(method, args); // 构造和调用,这里的restClient不保存状态 - RestClientBuilder builder = RestClient.create().url(determineUrl(restApi, context)).method(restApi.method()).config(config); + RestClientBuilder builder = RestClient.create().url(resolveUrl(method.getUrl(), context)) + .method(method.getMethod()) + .config(config); // 需要带cookie的带上 - if (restApi.credentials()) { + if (method.isCredentials()) { builder.withCredential(); } // 判断情况,赋值参数 @@ -162,7 +160,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab // 设置客户端 client.setClient(registry.getProvider()); // 是否对结果进行映射 - boolean map = null != mapping && null == AnnotationUtils.findAnnotation(method, Transient.class); + boolean map = null != mapping && method.isBare(); // 执行请求 Object result = execute(client, method, map); // 结果映射 @@ -177,7 +175,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab * @param map 是否映射结果 * @return 结果 */ - private Object execute(RestClient client, Method method, boolean map) throws IOException { + private Object execute(RestClient client, RestMethod method, boolean map) throws IOException { // 构建带泛型的返回值,自动判断是否是简单类型 JavaType constructed = JacksonUtil.getMapper().constructType(method.getGenericReturnType()); // 特殊处理映射 @@ -236,21 +234,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab * * @return 结果 */ - private String determineUrl(RestApi restApi, ArgumentResolveContext context) { - String url; - // 解析url以支持PathVariable - if (DataUtils.isNotBlank(restApi.url())) { - url = restApi.url(); - } else { - // 构建基础url,优先级从小到大依次找。同时尝试取字典值 - url = Stream.of(restApi.baseUrl(), this.baseUrl) - .filter(DataUtils::isNotBlank) - .findFirst() - // 判定和赋值 - .map(found -> found.startsWith("#") ? properties.getDictUrl(found.substring(1)) : found) - .map(base -> base + restApi.uri()) - .orElseThrow(() -> new IllegalArgumentException("【Rest调用】未指定url或baseurl,无法调用远端服务器!")); - } + private String resolveUrl(String url, ArgumentResolveContext context) { // 尝试解析路径参数 return context.hasPathParams() ? UrlCompiler.compile(url, context.getPathParams()) : url; } @@ -268,4 +252,25 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab } return properties.getAuthProvider(); } + + /** + * 如果调用到了Object类的方法,则绕行 + * + * @param method 方法 + * @param args 参数 + * @return 结果 + */ + @Deprecated + private Object passObjectMethod(Method method, Object[] args) { + // 处理基本方法被代理的情况 + if (AopUtils.isEqualsMethod(method)) { + Object obj = args[0]; + // The target does not implement the equals(Object) method itself. + return null != obj && ClassUtils.isAssignable(targetType, obj.getClass()); + } else if (AopUtils.isHashCodeMethod(method)) { + // The target does not implement the hashCode() method itself. + return -1; + } + return null; + } } diff --git a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/entity/RestMethod.java b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/entity/RestMethod.java new file mode 100644 index 0000000..a0eb409 --- /dev/null +++ b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/entity/RestMethod.java @@ -0,0 +1,117 @@ +package group.flyfish.rest.registry.proxy.entity; + +import group.flyfish.rest.annotation.RestApi; +import group.flyfish.rest.enums.HttpMethod; +import group.flyfish.rest.registry.proxy.RestProxyInvoker; +import group.flyfish.rest.utils.DataUtils; +import lombok.Getter; +import org.springframework.core.annotation.AnnotationUtils; + +import java.beans.Transient; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; +import java.util.stream.Stream; + +/** + * 表示单个请求的最小单元 + * + * @author wangyu + */ +public class RestMethod { + + // 方法参数缓存,避免clone + @Getter + private Parameter[] parameters; + + // 解析@Transient注解的结果 + @Getter + private boolean bare; + + // 解析后的路径 + @Getter + private String url; + + // http方法 + @Getter + private HttpMethod method; + + // 是否携带cookie + @Getter + private boolean credentials; + + // 多个参数时使用合并的body + @Getter + private boolean mergeBody; + + // 带泛型的返回类型 + @Getter + private Type genericReturnType; + + // 不带泛型的返回类型 + @Getter + private Class returnType; + + // 是否不可用状态 + @Getter + private boolean invalid; + + private RestMethod(Method method, RestProxyInvoker invoker) { + // 执行初始化 + init(method, invoker); + } + + /** + * 解析代理方法 + * + * @param method 方法 + * @return 结果 + */ + public static RestMethod resolve(Method method, RestProxyInvoker invoker) { + return new RestMethod(method, invoker); + } + + /** + * 初始化方法 + */ + private void init(Method method, RestProxyInvoker invoker) { + RestApi restApi = AnnotationUtils.findAnnotation(method, RestApi.class); + // 无视proxy,因为啥也没 + if (null == restApi) { + this.invalid = true; + return; + } + this.url = determineUrl(restApi, invoker); + this.method = restApi.method(); + this.credentials = restApi.credentials(); + this.mergeBody = restApi.mergedBody(); + this.parameters = method.getParameters(); + this.bare = null != AnnotationUtils.findAnnotation(method, Transient.class); + this.genericReturnType = method.getGenericReturnType(); + this.returnType = method.getReturnType(); + } + + /** + * 决定基本url,优先级: 方法注解url > 方法注解baseUrl + uri > 全局配置 + uri + * + * @return 结果 + */ + private String determineUrl(RestApi restApi, RestProxyInvoker invoker) { + String url; + // 解析url以支持PathVariable + if (DataUtils.isNotBlank(restApi.url())) { + return restApi.url(); + } else { + // 构建基础url,优先级从小到大依次找。同时尝试取字典值 + return Stream.of(restApi.baseUrl(), invoker.getBaseUrl()) + .filter(DataUtils::isNotBlank) + .findFirst() + // 判定和赋值 + .map(found -> found.startsWith("#") ? + invoker.getProperties().getDictUrl(found.substring(1)) : found) + .map(base -> base + restApi.uri()) + .orElseThrow(() -> new IllegalArgumentException("【Rest调用】未指定url或baseurl,无法调用远端服务器!")); + } + } + +} diff --git a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/ArgumentResolveContext.java b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/ArgumentResolveContext.java index 8ba537d..07ffb64 100644 --- a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/ArgumentResolveContext.java +++ b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/ArgumentResolveContext.java @@ -1,7 +1,7 @@ package group.flyfish.rest.registry.proxy.support; -import group.flyfish.rest.annotation.RestApi; import group.flyfish.rest.entity.Multipart; +import group.flyfish.rest.registry.proxy.entity.RestMethod; import group.flyfish.rest.utils.DataUtils; import lombok.Builder; import lombok.Data; @@ -18,8 +18,8 @@ import java.util.Map; @Builder public class ArgumentResolveContext { - // 注解 - private RestApi annotation; + // 解析的方法 + private RestMethod method; // 参数 private Map param; diff --git a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/RestArgumentResolverComposite.java b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/RestArgumentResolverComposite.java index 59596fe..e3526ca 100644 --- a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/RestArgumentResolverComposite.java +++ b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/RestArgumentResolverComposite.java @@ -1,8 +1,7 @@ package group.flyfish.rest.registry.proxy.support; -import group.flyfish.rest.annotation.RestApi; +import group.flyfish.rest.registry.proxy.entity.RestMethod; -import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.List; import java.util.stream.IntStream; @@ -24,14 +23,13 @@ public class RestArgumentResolverComposite { /** * 执行解析 * - * @param annotation 注解 - * @param method 方法 - * @param args 参数 + * @param method 方法 + * @param args 参数 * @return 结果 */ - public ArgumentResolveContext resolve(RestApi annotation, Method method, Object[] args) { + public ArgumentResolveContext resolve(RestMethod method, Object[] args) { // 上下文 - ArgumentResolveContext context = ArgumentResolveContext.builder().annotation(annotation).build(); + ArgumentResolveContext context = ArgumentResolveContext.builder().method(method).build(); // 参数元 Parameter[] parameters = method.getParameters(); // 循环处理 diff --git a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/resolvers/RestParamArgumentResolver.java b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/resolvers/RestParamArgumentResolver.java index 39faf12..271dfb8 100644 --- a/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/resolvers/RestParamArgumentResolver.java +++ b/rest-proxy-core/src/main/java/group/flyfish/rest/registry/proxy/support/resolvers/RestParamArgumentResolver.java @@ -53,7 +53,7 @@ public class RestParamArgumentResolver implements RestArgumentResolver { .filter(DataUtils::isNotBlank) .orElse(parameter.getName()); // 启用合并请求体,合并入 - if (context.getAnnotation().mergedBody()) { + if (context.getMethod().isMergeBody()) { context.setBody(name, value); } else { context.setParam(name, value);