feat: 升级1.0.7,重构执行器逻辑,增加方法缓存,提高并发性能
This commit is contained in:
parent
bf756ee743
commit
6aaa9b8cbe
4
pom.xml
4
pom.xml
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<groupId>group.flyfish</groupId>
|
<groupId>group.flyfish</groupId>
|
||||||
<artifactId>rest-proxy</artifactId>
|
<artifactId>rest-proxy</artifactId>
|
||||||
<version>1.0.6</version>
|
<version>1.0.7</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>8</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
@ -22,7 +22,7 @@
|
|||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<commons-collection.version>4.4</commons-collection.version>
|
<commons-collection.version>4.4</commons-collection.version>
|
||||||
<commons.lang.version>2.6</commons.lang.version>
|
<commons.lang.version>2.6</commons.lang.version>
|
||||||
<sdk.version>1.0.6</sdk.version>
|
<sdk.version>1.0.7</sdk.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>group.flyfish</groupId>
|
<groupId>group.flyfish</groupId>
|
||||||
<artifactId>rest-proxy</artifactId>
|
<artifactId>rest-proxy</artifactId>
|
||||||
<version>1.0.6</version>
|
<version>1.0.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>group.flyfish</groupId>
|
<groupId>group.flyfish</groupId>
|
||||||
<artifactId>rest-proxy</artifactId>
|
<artifactId>rest-proxy</artifactId>
|
||||||
<version>1.0.6</version>
|
<version>1.0.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package group.flyfish.rest.registry.proxy;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
import com.fasterxml.jackson.databind.JavaType;
|
||||||
import group.flyfish.rest.annotation.AutoMapping;
|
import group.flyfish.rest.annotation.AutoMapping;
|
||||||
import group.flyfish.rest.annotation.RestApi;
|
|
||||||
import group.flyfish.rest.annotation.RestService;
|
import group.flyfish.rest.annotation.RestService;
|
||||||
import group.flyfish.rest.configuration.RestClientProperties;
|
import group.flyfish.rest.configuration.RestClientProperties;
|
||||||
import group.flyfish.rest.configuration.configure.PropertiesConfigurable;
|
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.core.client.RestClientBuilder;
|
||||||
import group.flyfish.rest.mapping.RestResultMapping;
|
import group.flyfish.rest.mapping.RestResultMapping;
|
||||||
import group.flyfish.rest.registry.RestApiRegistry;
|
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.ArgumentResolveContext;
|
||||||
import group.flyfish.rest.registry.proxy.support.RestArgumentResolverComposite;
|
import group.flyfish.rest.registry.proxy.support.RestArgumentResolverComposite;
|
||||||
import group.flyfish.rest.registry.proxy.support.UrlCompiler;
|
import group.flyfish.rest.registry.proxy.support.UrlCompiler;
|
||||||
import group.flyfish.rest.registry.wrapper.DefaultRestResultMapping;
|
import group.flyfish.rest.registry.wrapper.DefaultRestResultMapping;
|
||||||
import group.flyfish.rest.utils.DataUtils;
|
import group.flyfish.rest.utils.DataUtils;
|
||||||
import group.flyfish.rest.utils.JacksonUtil;
|
import group.flyfish.rest.utils.JacksonUtil;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.http.client.config.RequestConfig;
|
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.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
import java.beans.Transient;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rest代理执行器
|
* Rest代理执行器
|
||||||
@ -42,13 +42,17 @@ import java.util.stream.Stream;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurable {
|
public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurable {
|
||||||
|
|
||||||
|
// 方法缓存
|
||||||
|
private final Map<Integer, RestMethod> methods = new ConcurrentHashMap<>();
|
||||||
// 要代理的目标类
|
// 要代理的目标类
|
||||||
private final Class<?> targetType;
|
private final Class<?> targetType;
|
||||||
// 服务映射
|
// 服务映射
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
// 配置属性
|
// 配置属性
|
||||||
|
@Getter
|
||||||
private RestClientProperties properties;
|
private RestClientProperties properties;
|
||||||
// 初始的基本路径
|
// 初始的基本路径
|
||||||
|
@Getter
|
||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
// 超时时间
|
// 超时时间
|
||||||
private RequestConfig config;
|
private RequestConfig config;
|
||||||
@ -59,6 +63,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab
|
|||||||
// 鉴权提供者
|
// 鉴权提供者
|
||||||
private RestAuthProvider authProvider;
|
private RestAuthProvider authProvider;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造器
|
* 构造器
|
||||||
*
|
*
|
||||||
@ -103,34 +108,27 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab
|
|||||||
* 执行rest请求的地方,这里很简单易懂
|
* 执行rest请求的地方,这里很简单易懂
|
||||||
*
|
*
|
||||||
* @param proxy 代理对象
|
* @param proxy 代理对象
|
||||||
* @param method 代理方法
|
* @param target 代理方法
|
||||||
* @param args 参数
|
* @param args 参数
|
||||||
* @return 结果
|
* @return 结果
|
||||||
* @throws Throwable 可能抛出的异常
|
* @throws Throwable 可能抛出的异常
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
public Object invoke(Object proxy, Method target, Object[] args) throws Throwable {
|
||||||
// 处理基本方法被代理的情况
|
// 解析方法,做基本验证
|
||||||
if (AopUtils.isEqualsMethod(method)) {
|
RestMethod method = methods.computeIfAbsent(target.hashCode(), k -> RestMethod.resolve(target, this));
|
||||||
Object obj = args[0];
|
if (method.isInvalid()) {
|
||||||
// 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) {
|
|
||||||
throw new IllegalAccessException("【Rest调用】未声明rest配置的方法被调用!请检查代码!");
|
throw new IllegalAccessException("【Rest调用】未声明rest配置的方法被调用!请检查代码!");
|
||||||
}
|
}
|
||||||
RestArgumentResolverComposite composite = registry.getComposite();
|
RestArgumentResolverComposite composite = registry.getComposite();
|
||||||
// 第一步就解析参数
|
// 第一步就解析参数
|
||||||
ArgumentResolveContext context = composite.resolve(restApi, method, args);
|
ArgumentResolveContext context = composite.resolve(method, args);
|
||||||
// 构造和调用,这里的restClient不保存状态
|
// 构造和调用,这里的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的带上
|
// 需要带cookie的带上
|
||||||
if (restApi.credentials()) {
|
if (method.isCredentials()) {
|
||||||
builder.withCredential();
|
builder.withCredential();
|
||||||
}
|
}
|
||||||
// 判断情况,赋值参数
|
// 判断情况,赋值参数
|
||||||
@ -162,7 +160,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab
|
|||||||
// 设置客户端
|
// 设置客户端
|
||||||
client.setClient(registry.getProvider());
|
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);
|
Object result = execute(client, method, map);
|
||||||
// 结果映射
|
// 结果映射
|
||||||
@ -177,7 +175,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab
|
|||||||
* @param map 是否映射结果
|
* @param map 是否映射结果
|
||||||
* @return 结果
|
* @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());
|
JavaType constructed = JacksonUtil.getMapper().constructType(method.getGenericReturnType());
|
||||||
// 特殊处理映射
|
// 特殊处理映射
|
||||||
@ -236,21 +234,7 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab
|
|||||||
*
|
*
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
private String determineUrl(RestApi restApi, ArgumentResolveContext context) {
|
private String resolveUrl(String url, 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,无法调用远端服务器!"));
|
|
||||||
}
|
|
||||||
// 尝试解析路径参数
|
// 尝试解析路径参数
|
||||||
return context.hasPathParams() ? UrlCompiler.compile(url, context.getPathParams()) : url;
|
return context.hasPathParams() ? UrlCompiler.compile(url, context.getPathParams()) : url;
|
||||||
}
|
}
|
||||||
@ -268,4 +252,25 @@ public class RestProxyInvoker implements InvocationHandler, PropertiesConfigurab
|
|||||||
}
|
}
|
||||||
return properties.getAuthProvider();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,无法调用远端服务器!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package group.flyfish.rest.registry.proxy.support;
|
package group.flyfish.rest.registry.proxy.support;
|
||||||
|
|
||||||
import group.flyfish.rest.annotation.RestApi;
|
|
||||||
import group.flyfish.rest.entity.Multipart;
|
import group.flyfish.rest.entity.Multipart;
|
||||||
|
import group.flyfish.rest.registry.proxy.entity.RestMethod;
|
||||||
import group.flyfish.rest.utils.DataUtils;
|
import group.flyfish.rest.utils.DataUtils;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -18,8 +18,8 @@ import java.util.Map;
|
|||||||
@Builder
|
@Builder
|
||||||
public class ArgumentResolveContext {
|
public class ArgumentResolveContext {
|
||||||
|
|
||||||
// 注解
|
// 解析的方法
|
||||||
private RestApi annotation;
|
private RestMethod method;
|
||||||
|
|
||||||
// 参数
|
// 参数
|
||||||
private Map<String, Object> param;
|
private Map<String, Object> param;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package group.flyfish.rest.registry.proxy.support;
|
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.lang.reflect.Parameter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
@ -24,14 +23,13 @@ public class RestArgumentResolverComposite {
|
|||||||
/**
|
/**
|
||||||
* 执行解析
|
* 执行解析
|
||||||
*
|
*
|
||||||
* @param annotation 注解
|
* @param method 方法
|
||||||
* @param method 方法
|
* @param args 参数
|
||||||
* @param args 参数
|
|
||||||
* @return 结果
|
* @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();
|
Parameter[] parameters = method.getParameters();
|
||||||
// 循环处理
|
// 循环处理
|
||||||
|
@ -53,7 +53,7 @@ public class RestParamArgumentResolver implements RestArgumentResolver {
|
|||||||
.filter(DataUtils::isNotBlank)
|
.filter(DataUtils::isNotBlank)
|
||||||
.orElse(parameter.getName());
|
.orElse(parameter.getName());
|
||||||
// 启用合并请求体,合并入
|
// 启用合并请求体,合并入
|
||||||
if (context.getAnnotation().mergedBody()) {
|
if (context.getMethod().isMergeBody()) {
|
||||||
context.setBody(name, value);
|
context.setBody(name, value);
|
||||||
} else {
|
} else {
|
||||||
context.setParam(name, value);
|
context.setParam(name, value);
|
||||||
|
Loading…
Reference in New Issue
Block a user