group.flyfish.rest.registry.proxy.RestProxyInvoker Maven / Gradle / Ivy
package group.flyfish.rest.registry.proxy;
import com.fasterxml.jackson.databind.JavaType;
import group.flyfish.rest.annotation.AutoMapping;
import group.flyfish.rest.annotation.RestService;
import group.flyfish.rest.configuration.RestClientProperties;
import group.flyfish.rest.configuration.configure.PropertiesConfigurable;
import group.flyfish.rest.core.auth.RestAuthProvider;
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;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
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.concurrent.ConcurrentHashMap;
/**
* Rest代理执行器
*
* @author wangyu
*/
@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;
// 注册器,包含基础信息
private final RestApiRegistry registry;
// 结果映射
private RestResultMapping mapping;
// 鉴权提供者
private RestAuthProvider authProvider;
/**
* 构造器
*
* @param targetType 目标类型
* @param registry 注册器
*/
private RestProxyInvoker(Class> targetType, RestApiRegistry registry) {
this.targetType = targetType;
this.registry = registry;
// 注解的优先级高于全局基本路径
this.restService = AnnotationUtils.findAnnotation(targetType, RestService.class);
Assert.notNull(restService, "当前类尚未添加@RestService注解!");
}
/**
* 生产一个实现类
*
* @param target 目标
* @param 泛型
* @return 结果
*/
public static T produce(Class> target, RestApiRegistry registry) {
RestProxyInvoker invoker = new RestProxyInvoker(target, registry);
RestInvokers.add(invoker);
return DataUtils.cast(Proxy.newProxyInstance(target.getClassLoader(), new Class[]{target}, invoker));
}
/**
* 完成配置
*
* @param properties 属性
*/
@Override
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();
this.authProvider = determineAuthProvider();
}
/**
* 执行rest请求的地方,这里很简单易懂
*
* @param proxy 代理对象
* @param target 代理方法
* @param args 参数
* @return 结果
* @throws Throwable 可能抛出的异常
*/
@Override
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(method, args);
// 构造和调用,这里的restClient不保存状态
RestClientBuilder builder = RestClient.create().url(resolveUrl(method.getUrl(), context))
.method(method.getMethod())
.config(config);
// 需要带cookie的带上
if (method.isCredentials()) {
builder.withCredential();
}
// 判断情况,赋值参数
if (context.hasBody()) {
builder.body(context.getBody());
}
// 赋值文件体
if (context.hasMultipart()) {
builder.multipart();
context.getFiles().forEach((key, value) -> {
value.setFilename(context.getFilename(key, value.getFilename()));
builder.addMultipartBody(value);
});
}
// 赋值参数们
if (context.hasParams()) {
builder.queryParams(context.getParam());
}
// 赋值头
if (context.hasHeaders()) {
builder.headers(context.getHeaders());
}
// 添加鉴权信息
if (null != authProvider) {
authProvider.provide(builder);
}
// 构建客户端
RestClient client = builder.build();
// 设置客户端
client.setClient(registry.getProvider());
// 是否对结果进行映射
boolean map = null != mapping && method.isBare();
// 执行请求
Object result = execute(client, method, map);
// 结果映射
return map ? mapping.map(result) : result;
}
/**
* 最终执行的方法
*
* @param client rest客户端实例
* @param method 原方法实例
* @param map 是否映射结果
* @return 结果
*/
private Object execute(RestClient client, RestMethod method, boolean map) throws IOException {
// 构建带泛型的返回值,自动判断是否是简单类型
JavaType constructed = JacksonUtil.getMapper().constructType(method.getGenericReturnType());
// 特殊处理映射
if (map) {
Type resolved = mapping.resolve(constructed);
// 返回java泛型
if (resolved instanceof JavaType) {
return client.execute((JavaType) resolved);
} else if (resolved instanceof Class) {
// 简单类型
return client.execute((Class>) resolved);
}
}
// 优先构建,对于map来说,只支持模糊map,否则可能会报错,直接返回
if (ClassUtils.isAssignable(Map.class, method.getReturnType())) {
return client.executeForMap();
}
// 不是map,直接返回构建结果类型
return client.execute(constructed);
}
/**
* 找到配置固化的基本url
*/
private String findBaseUrl() {
// 当且仅当存在时进入
if (null != restService) {
// 注解的路径解析
String key = restService.value();
String baseUrl = restService.baseUrl();
// 更友好的处理解包
AutoMapping autoMapping = AnnotationUtils.findAnnotation(targetType, AutoMapping.class);
if (null != autoMapping) {
// 找到返回值处理器
Class> clazz = autoMapping.value();
// 处理返回值
if (Object.class.equals(clazz)) {
this.mapping = DefaultRestResultMapping.getInstance();
} else {
this.mapping = RestResultMapping.MAPPINGS.get(clazz);
}
}
// 当key不为空,解析字典路径
if (DataUtils.isNotBlank(key)) {
return properties.getDictUrl(key);
} else if (DataUtils.isNotBlank(baseUrl)) {
return baseUrl;
}
}
// 解包生效,以标准模式解包
return properties.getBaseUrl();
}
/**
* 决定基本url,优先级: 方法注解url > 方法注解baseUrl + uri > 全局配置 + uri
*
* @return 结果
*/
private String resolveUrl(String url, ArgumentResolveContext context) {
// 尝试解析路径参数
return context.hasPathParams() ? UrlCompiler.compile(url, context.getPathParams()) : url;
}
/**
* 确定鉴权提供者
*
* @return 实例化的提供者
*/
@SneakyThrows
private RestAuthProvider determineAuthProvider() {
Class> candidate = restService.authProvider();
if (ClassUtils.isAssignable(RestAuthProvider.class, candidate)) {
return (RestAuthProvider) candidate.newInstance();
}
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;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy