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>
|
||||
<artifactId>rest-proxy</artifactId>
|
||||
<version>1.0.6</version>
|
||||
<version>1.0.7</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
@ -22,7 +22,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<commons-collection.version>4.4</commons-collection.version>
|
||||
<commons.lang.version>2.6</commons.lang.version>
|
||||
<sdk.version>1.0.6</sdk.version>
|
||||
<sdk.version>1.0.7</sdk.version>
|
||||
</properties>
|
||||
|
||||
<packaging>pom</packaging>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>group.flyfish</groupId>
|
||||
<artifactId>rest-proxy</artifactId>
|
||||
<version>1.0.6</version>
|
||||
<version>1.0.7</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>group.flyfish</groupId>
|
||||
<artifactId>rest-proxy</artifactId>
|
||||
<version>1.0.6</version>
|
||||
<version>1.0.7</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -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<Integer, RestMethod> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
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<String, Object> param;
|
||||
|
@ -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();
|
||||
// 循环处理
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user