feat: 优化代码,清理冗余项目,修复超时时间

This commit is contained in:
wangyu 2023-01-11 10:55:33 +08:00
parent 4345b9543a
commit 605615d370
21 changed files with 305 additions and 80 deletions

11
pom.xml
View File

@ -20,7 +20,6 @@
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<fastjson.version>2.0.22</fastjson.version>
<commons-collection.version>4.4</commons-collection.version>
<commons.lang.version>2.6</commons.lang.version>
<sdk.version>1.0.0</sdk.version>
@ -46,21 +45,11 @@
<artifactId>commons-collections4</artifactId>
<version>${commons-collection.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.10.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>group.flyfish</groupId>
<artifactId>rest-proxy-api</artifactId>

View File

@ -31,5 +31,5 @@ public @interface RestService {
*
* @return 结果
*/
long timeout() default -1L;
int timeout() default -1;
}

View File

@ -57,10 +57,6 @@
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -1,18 +1,15 @@
package group.flyfish.rest.client;
package group.flyfish.rest.core.client;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.exception.RestClientException;
import group.flyfish.rest.core.produce.HttpClientProducer;
import group.flyfish.rest.enums.ResponseType;
import group.flyfish.rest.utils.JacksonUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import group.flyfish.rest.core.exception.RestClientException;
import group.flyfish.rest.enums.ResponseType;
import group.flyfish.rest.utils.JacksonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
@ -27,7 +24,7 @@ import java.util.function.Consumer;
import static group.flyfish.rest.constants.RestConstants.DEFAULT_EXECUTOR;
/**
* Rest请求客户端
* Rest请求客户端 Apache http实现
*
* @author Mr.Wang
* <p>
@ -39,9 +36,8 @@ import static group.flyfish.rest.constants.RestConstants.DEFAULT_EXECUTOR;
* 6. 新增单例httpClient模式复用连接让应用更高效
*/
@Slf4j
public final class RestClient {
final class DefaultRestClient implements RestClient {
private static volatile CloseableHttpClient client;
private final HttpRequestBase request;
private boolean async = false;
private Consumer<HttpEntity> consumer;
@ -57,34 +53,17 @@ public final class RestClient {
*
* @param request 请求信息
*/
public RestClient(HttpRequestBase request) {
DefaultRestClient(HttpRequestBase request) {
this.request = request;
}
/**
* 设置单例的客户端
*
* @param client 客户端
*/
public static void setClient(CloseableHttpClient client) {
RestClient.client = client;
}
/**
* 新增一个构建器
*
* @return 结果
*/
public static RestClientBuilder create() {
return new RestClientBuilder();
}
/**
* 设置请求失败时的回调
*
* @param errorConsumer 错误回调
* @return 结果
*/
@Override
public RestClient onError(Consumer<RestClientException> errorConsumer) {
this.errorConsumer = errorConsumer;
return this;
@ -109,6 +88,7 @@ public final class RestClient {
* @param responseType 响应类型
* @return 结果
*/
@Override
public RestClient responseType(ResponseType responseType) {
this.responseType = responseType;
return this;
@ -119,6 +99,7 @@ public final class RestClient {
*
* @return 结果
*/
@Override
public RestClient async() {
this.async = true;
this.executorService = DEFAULT_EXECUTOR;
@ -131,6 +112,7 @@ public final class RestClient {
* @param executorService 线程池
* @return 结果
*/
@Override
public RestClient async(ExecutorService executorService) {
this.async = true;
this.executorService = executorService;
@ -142,6 +124,7 @@ public final class RestClient {
*
* @param consumer 结果
*/
@Override
public void execute(Consumer<HttpEntity> consumer) {
this.consumer = consumer;
if (this.async) {
@ -157,6 +140,7 @@ public final class RestClient {
/**
* 静默执行抛弃全部异常
*/
@Override
public void executeSilent() {
executeSafety();
}
@ -167,6 +151,7 @@ public final class RestClient {
* @return map
* @throws IOException 异常
*/
@Override
public Map<String, Object> executeForMap() throws IOException {
this.responseType = ResponseType.JSON;
return innerExecute();
@ -178,6 +163,7 @@ public final class RestClient {
* @return 字符串
* @throws IOException 异常
*/
@Override
public String executeForString() throws IOException {
this.responseType = ResponseType.TEXT;
return innerExecute();
@ -202,13 +188,14 @@ public final class RestClient {
* @return 结果
*/
@Nullable
@Override
public <T> T execute(Class<T> clazz) {
this.responseType = ResponseType.OBJECT;
this.resultClass = clazz;
try {
return innerExecute();
} catch (IOException e) {
e.printStackTrace();
log.error("请求时发生异常!", e);
}
return null;
}
@ -221,25 +208,34 @@ public final class RestClient {
* @return 结果
*/
@Nullable
@Override
public <T> T execute(JavaType type) {
this.responseType = ResponseType.OBJECT;
this.resultType = type;
try {
return innerExecute();
} catch (IOException e) {
e.printStackTrace();
log.error("请求时发生异常!", e);
}
return null;
}
/**
* 执行序列化使用类型引用
*
* @param typeReference jackson 类型引用
* @param <T> 泛型
* @return 序列化结果
*/
@Nullable
@Override
public <T> T execute(TypeReference<T> typeReference) {
this.responseType = ResponseType.OBJECT;
this.typeReference = typeReference;
try {
return innerExecute();
} catch (IOException e) {
e.printStackTrace();
log.error("请求时发生异常!", e);
}
return null;
}
@ -250,10 +246,12 @@ public final class RestClient {
* @return 响应实体
* @throws IOException 异常
*/
@Override
public <T> T execute() throws IOException {
return innerExecute();
}
/**
* 内部执行方法预处理结果
*
@ -261,11 +259,8 @@ public final class RestClient {
* @return 结果
*/
private <T> T innerExecute() throws IOException {
if (null == client) {
client = HttpClientProducer.produce();
}
log.info("【Rest Invoke】{} {}", request.getMethod(), request.getURI());
try (CloseableHttpResponse response = client.execute(request)) {
try (CloseableHttpResponse response = HttpClientCache.getClient().execute(request)) {
StatusLine statusLine = response.getStatusLine();
if (200 == statusLine.getStatusCode()) {
HttpEntity entity = response.getEntity();

View File

@ -0,0 +1,41 @@
package group.flyfish.rest.core.client;
import group.flyfish.rest.core.produce.HttpClientProducer;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
/**
* http请求客户端缓存
*
* @author wangyu
*/
class HttpClientCache {
private volatile CloseableHttpClient client;
private static final HttpClientCache INSTANCE = new HttpClientCache();
/**
* 获取共享client
*
* @return 结果
*/
CloseableHttpClient computeClient() throws IOException {
if (null == client) {
synchronized (INSTANCE) {
if (null != client) return client;
return client = HttpClientProducer.produce();
}
}
return client;
}
public static CloseableHttpClient getClient() throws IOException {
return INSTANCE.computeClient();
}
public static void setClient(CloseableHttpClient client) {
INSTANCE.client = client;
}
}

View File

@ -0,0 +1,144 @@
package group.flyfish.rest.core.client;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import group.flyfish.rest.core.exception.RestClientException;
import group.flyfish.rest.enums.ResponseType;
import org.apache.http.HttpEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.lang.Nullable;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
/**
* Rest请求客户端
*
* @author Mr.Wang
* <p>
* @apiNote 1. 全builder调用用户系统内部相互通信
* 2. 支持异步回调
* 3. 多样性组合
* 4. 解耦实现
* 5. 支持上传文件FormDataJSON支持自定义无侵入扩展
* 6. 新增单例httpClient模式复用连接让应用更高效
*/
public interface RestClient {
/**
* 新增一个构建器
*
* @return 结果
*/
static RestClientBuilder create() {
return new RestClientBuilder();
}
/**
* 设置单例的客户端
*
* @param client 客户端
*/
static void setClient(CloseableHttpClient client) {
HttpClientCache.setClient(client);
}
/**
* 标记线程池执行
*
* @return 结果
*/
RestClient async();
/**
* 标记指定线程池执行
*
* @param executorService 线程池
* @return 结果
*/
RestClient async(ExecutorService executorService);
/**
* 设置响应类型
*
* @param responseType 响应类型
* @return 结果
*/
RestClient responseType(ResponseType responseType);
/**
* 异步执行接收结果
*
* @param consumer 结果
*/
void execute(Consumer<HttpEntity> consumer);
/**
* 静默执行抛弃全部异常
*/
void executeSilent();
/**
* 执行请求返回Map
*
* @return map
* @throws IOException 异常
*/
Map<String, Object> executeForMap() throws IOException;
/**
* 执行请求返回字符串
*
* @return 字符串
* @throws IOException 异常
*/
String executeForString() throws IOException;
/**
* 执行并序列化该方法会安全的返回对象或者空
*
* @param clazz
* @param <T> 泛型
* @return 结果
*/
@Nullable
<T> T execute(Class<T> clazz);
/**
* 执行并序列化使用复杂的自动构造的类型
*
* @param type jackson的强化类型
* @param <T> 泛型
* @return 结果
*/
@Nullable
<T> T execute(JavaType type);
/**
* 执行序列化使用类型引用
*
* @param typeReference jackson 类型引用
* @param <T> 泛型
* @return 序列化结果
*/
@Nullable
<T> T execute(TypeReference<T> typeReference);
/**
* 执行请求返回响应实体自行处理
*
* @return 响应实体
* @throws IOException 异常
*/
<T> T execute() throws IOException;
/**
* 设置请求失败时的回调
*
* @param errorConsumer 错误回调
* @return 结果
*/
RestClient onError(Consumer<RestClientException> errorConsumer);
}

View File

@ -1,11 +1,11 @@
package group.flyfish.rest.core.builder;
package group.flyfish.rest.core.client;
import group.flyfish.rest.client.RestClient;
import group.flyfish.rest.core.entity.Multipart;
import group.flyfish.rest.enums.HttpMethod;
import group.flyfish.rest.utils.DataUtils;
import group.flyfish.rest.utils.JacksonUtil;
import group.flyfish.rest.utils.RequestContext;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpRequestBase;
import java.nio.charset.Charset;
@ -42,6 +42,8 @@ public class RestClientBuilder {
private String charset;
private RequestConfig config;
public String getUrl() {
return url;
}
@ -109,6 +111,11 @@ public class RestClientBuilder {
return this;
}
public RestClientBuilder config(RequestConfig config) {
this.config = config;
return this;
}
public Charset getCharset() {
return DataUtils.isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset);
}
@ -179,7 +186,7 @@ public class RestClientBuilder {
// 添加头
getHeaders().forEach(request::addHeader);
// 设置公共设置
request.setConfig(REQUEST_CONFIG);
request.setConfig(null == config ? REQUEST_CONFIG : config);
// 返回
return request;
}
@ -192,8 +199,7 @@ public class RestClientBuilder {
public RestClient build() {
// 创建请求
HttpRequestBase request = buildRequest();
return new RestClient(request);
return new DefaultRestClient(request);
}
}

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.core.resolver.support.AbstractParamResolver;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpRequestBase;

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.core.resolver.support.AbstractParamResolver;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpRequestBase;

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import org.apache.http.client.methods.HttpRequestBase;
/**

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.core.resolver.support.AbstractBodyResolver;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpRequestBase;

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.core.resolver.support.AbstractBodyResolver;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.core.resolver.support.AbstractBodyResolver;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;

View File

@ -1,8 +1,7 @@
package group.flyfish.rest.core.resolver.support;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.utils.DataUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
@ -54,11 +53,11 @@ public abstract class AbstractBodyResolver {
String filename = multipart.getFilename();
if (data instanceof byte[]) {
builder.addBinaryBody(name, (byte[]) data,
ContentType.create(MIME_MAP.getOrDefault(FilenameUtils.getExtension(filename),
ContentType.create(MIME_MAP.getOrDefault(DataUtils.getExtension(filename),
ContentType.APPLICATION_OCTET_STREAM.getMimeType())), filename);
} else if (data instanceof File) {
builder.addBinaryBody(name, (File) data,
ContentType.create(MIME_MAP.getOrDefault(FilenameUtils.getExtension(filename),
ContentType.create(MIME_MAP.getOrDefault(DataUtils.getExtension(filename),
ContentType.APPLICATION_OCTET_STREAM.getMimeType())), filename);
} else {
throw new IllegalArgumentException("上传时,输入的数据不被支持!");

View File

@ -1,6 +1,6 @@
package group.flyfish.rest.core.resolver.support;
import group.flyfish.rest.core.builder.RestClientBuilder;
import group.flyfish.rest.core.client.RestClientBuilder;
import group.flyfish.rest.utils.DataUtils;
import java.util.stream.Collectors;

View File

@ -2,7 +2,7 @@ package group.flyfish.rest.registry;
import group.flyfish.rest.annotation.EnableRestApiProxy;
import group.flyfish.rest.annotation.RestService;
import group.flyfish.rest.client.RestClient;
import group.flyfish.rest.core.client.RestClient;
import group.flyfish.rest.configuration.RestClientProperties;
import group.flyfish.rest.core.produce.HttpClientProducer;
import group.flyfish.rest.registry.proxy.RestProxyInvoker;

View File

@ -1,11 +1,12 @@
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.client.RestClient;
import group.flyfish.rest.configuration.RestClientProperties;
import group.flyfish.rest.core.builder.RestClientBuilder;
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.proxy.support.ArgumentResolveContext;
import group.flyfish.rest.registry.proxy.support.RestArgumentResolverComposite;
@ -13,7 +14,8 @@ 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 com.fasterxml.jackson.databind.JavaType;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
@ -34,19 +36,25 @@ import java.util.stream.Stream;
*
* @author wangyu
*/
@Slf4j
public class RestProxyInvoker<T> implements InvocationHandler {
// 要代理的目标类
private final Class<T> targetType;
// 解析集合
private final RestArgumentResolverComposite composite;
// 服务映射
private final RestService restService;
// 初始的基本路径
private String baseUrl;
// 超时时间
private RequestConfig config;
// 基础url
private RestClientProperties properties;
// 结果映射
private RestResultMapping mapping;
/**
* 构造器
*
@ -56,6 +64,8 @@ public class RestProxyInvoker<T> implements InvocationHandler {
public RestProxyInvoker(Class<T> targetType, RestArgumentResolverComposite composite) {
this.targetType = targetType;
this.composite = composite;
// 注解的优先级高于全局基本路径
this.restService = AnnotationUtils.findAnnotation(targetType, RestService.class);
}
/**
@ -78,6 +88,10 @@ public class RestProxyInvoker<T> implements InvocationHandler {
*/
public void configure(RestClientProperties properties) {
this.properties = properties;
this.config = RequestConfig.custom()
.setConnectTimeout((int) properties.getConnectionTimeout().toMillis())
.setSocketTimeout(restService.timeout())
.build();
this.baseUrl = this.findBaseUrl();
}
@ -112,7 +126,8 @@ public class RestProxyInvoker<T> implements InvocationHandler {
// 构造和调用这里的restClient不保存状态
RestClientBuilder builder = RestClient.create()
.url(determineUrl(restApi, context))
.method(restApi.method());
.method(restApi.method())
.config(config);
// 需要带cookie的带上
if (restApi.credentials()) {
builder.withCredential();
@ -173,8 +188,6 @@ public class RestProxyInvoker<T> implements InvocationHandler {
* 找到配置固化的基本url
*/
private String findBaseUrl() {
// 注解的优先级高于全局基本路径
RestService restService = AnnotationUtils.findAnnotation(targetType, RestService.class);
// 当且仅当存在时进入
if (null != restService) {
// 注解的路径解析

View File

@ -13,7 +13,19 @@ import java.util.Map;
*/
public final class DataUtils {
public static final int INDEX_NOT_FOUND = -1;
private static final int INDEX_NOT_FOUND = -1;
private static final String EXTENSION_SEPARATOR = ".";
/**
* The Unix separator character.
*/
private static final char UNIX_SEPARATOR = '/';
/**
* The Windows separator character.
*/
private static final char WINDOWS_SEPARATOR = '\\';
/**
* 判断字符串是否不为空
@ -109,4 +121,34 @@ public final class DataUtils {
public static boolean isTrue(Boolean value) {
return Boolean.TRUE.equals(value);
}
public static String getExtension(final String filename) {
if (filename == null) {
return null;
}
final int index = indexOfExtension(filename);
if (index == INDEX_NOT_FOUND) {
return "";
} else {
return filename.substring(index + 1);
}
}
public static int indexOfExtension(final String filename) {
if (filename == null) {
return INDEX_NOT_FOUND;
}
final int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
final int lastSeparator = indexOfLastSeparator(filename);
return lastSeparator > extensionPos ? INDEX_NOT_FOUND : extensionPos;
}
public static int indexOfLastSeparator(final String filename) {
if (filename == null) {
return INDEX_NOT_FOUND;
}
final int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
final int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
return Math.max(lastUnixPos, lastWindowsPos);
}
}

View File

@ -1,6 +1,6 @@
package group.flyfish.rest;
import group.flyfish.rest.client.RestClient;
import group.flyfish.rest.core.client.RestClient;
import group.flyfish.rest.core.builder.MapParamBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;

View File

@ -52,7 +52,7 @@ public class RestProxyTest {
log.info(items.toString());
}
@RestService(baseUrl = "http://60.221.255.208:18092/api/")
@RestService(baseUrl = "http://60.221.255.208:18092/api/", timeout = 500)
@AutoMapping(TestRestResultMapping.class)
public interface TestRestService {
@ -61,7 +61,7 @@ public class RestProxyTest {
}
@RestService(baseUrl = "http://220.194.160.4:8083/interface")
@RestService(baseUrl = "http://220.194.160.4:8083/interface", timeout = 500)
@AutoMapping(TestRestResultMapping.class)
public interface TestPostService {

View File

@ -1,6 +1,6 @@
rest:
client:
connection-timeout: 30s
connection-timeout: 10s
base-url: http://localhost:8089
always-trust: true
urls: