// Feign的最核心类,该对象负责设置Feign相关的绝大部分东西
public abstract class Feign {
// 构建Feign的Builder对象
public static Builder builder() {
return new Builder();
}
// 生成配置的KEY
public static String configKey(Class targetType, Method method) {
StringBuilder builder = new StringBuilder();
builder.append(targetType.getSimpleName());
builder.append('#').append(method.getName()).append('(');
for (Type param : method.getGenericParameterTypes()) {
param = Types.resolve(targetType, targetType, param);
builder.append(Types.getRawType(param).getSimpleName()).append(',');
}
if (method.getParameterTypes().length > 0) {
builder.deleteCharAt(builder.length() - 1);
}
return builder.append(')').toString();
}
// 根据FeignClient的目标对象生成代理对象
public abstract <T> T newInstance(Target<T> target);
// 构建Feign的Builder对象
public static class Builder extends BaseBuilder<Builder> {
// 发送请求的客户端对象,默认使用HttpURLConnection发送请求
// @TODO
private Client client = new Client.Default(null, null);
public <T> T target(Class<T> apiType, String url) {
return target(new HardCodedTarget<>(apiType, url));
}
public <T> T target(Target<T> target) {
Feign feign = this.build();
return feign.newInstance(target);
}
// 构建Feign对象
public Feign build() {
// 增强当前类的字段信息
super.enrich();
// 创建响应的处理器对象,用来处理响应结果
final ResponseHandler responseHandler = new ResponseHandler(logLevel, logger, decoder, errorDecoder, dismiss404, closeAfterDecode, responseInterceptor);
// 创建生成方法处理器的工厂,方法处理器是用来执行方法的
SynchronousMethodHandler.Factory<Object> methodHandlerFactory = new SynchronousMethodHandler.Factory(
client, retryer, requestInterceptors, responseHandler, logger, logLevel, propagationPolicy,
// 请求模板RequestTemplate的工厂解析器
// 通过该解析器可以解析到RequestTemplateFactory,然通过RequestTemplateFactory创建RequestTemplate对象
new RequestTemplateFactoryResolver(encoder, queryMapEncoder), options);
// 创建基于反射的Feign对象
return new ReflectiveFeign<>(contract, methodHandlerFactory, invocationHandlerFactory, () -> null);
}
}
}
// 构建Feign对象的Builder对象,内部包含Feing的所有核心组件
public abstract class BaseBuilder<B extends BaseBuilder<B>> {
// 当前Builder对象
private final B thisB;
// 请求拦截器
protected final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
// 响应拦截器 @TODO
protected ResponseInterceptor responseInterceptor = ResponseInterceptor.DEFAULT;
// Feign的日志级别
protected Logger.Level logLevel = Logger.Level.NONE;
// Contract 接口定义了如何根据 Java 接口的注解创建请求和解析响应
// Contract 接口是 Feign 的一个核心接口,它可以自定义 Feign 客户端与服务端之间的契约规则,例如支持不同的注解风格、参数传递方式等
// 通过实现自定义的 Contract 接口,可以更灵活地定制 Feign 客户端与服务端之间的通信行为
// @TODO 看看下面的Default到底做了什么,这些都是Feign的核心组件
protected Contract contract = new Contract.Default();
// 重试机制
protected Retryer retryer = new Retryer.Default();
// 日志对象
protected Logger logger = new NoOpLogger();
// 编码(就是将参数解析为请求体)对象
protected Encoder encoder = new Encoder.Default();
// 解码对象(就是将响应体解码为返回值)
protected Decoder decoder = new Decoder.Default();
// 解码之后是否关闭资源
protected boolean closeAfterDecode = true;
// 对jpa请求参数转换为map的编码器
protected QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
// 异常解码器,该对象解码会得到一个异常对象
protected ErrorDecoder errorDecoder = new ErrorDecoder.Default();
// 请求的配置信息
protected Options options = new Options();
// 创建JDK动态代理中的InvocationHandler的对象
protected InvocationHandlerFactory invocationHandlerFactory = new InvocationHandlerFactory.Default();
// 是否应该解码404而不是抛出feigexception,默认为false
// 如果为true,404也会返回对应的结果
protected boolean dismiss404;
// 该对象是用于设定Feign异常的传播策略
protected ExceptionPropagationPolicy propagationPolicy = NONE;
// 该对象是用于将以上描述的组件进行增强的接口
// 该接口的定义: A enrich (A a){return a;},给你指定参数,让你增强,返回增强后的组件
protected List<Capability> capabilities = new ArrayList<>();
public BaseBuilder() {
thisB = (B) this;
}
// 增强当前类的字段信息
public B enrich() {
// 如果不存在增强器,不处理
if (capabilities.isEmpty()) {
return thisB;
}
// 获取到当前类的所有字段信息
this.getFieldsToEnrich().forEach(field -> {
field.setAccessible(true);
// 获取原来的值
final Object originalValue = field.get(thisB);
// 增强的值
final Object enriched;
// 如果是List
if (originalValue instanceof List) {
// 获取到泛型信息
Type ownerType = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
// 对List的每一个元素进行增强
enriched = ((List) originalValue).stream()
.map(value -> Capability.enrich(value, (Class<?>) ownerType, capabilities))
.collect(Collectors.toList());
} else {
// 单独对某个字段增强,方法定义: A aa(A a){ return a;}
enriched = Capability.enrich(originalValue, field.getType(), capabilities);
}
// 将字段变成增强后的字段
field.set(thisB, enriched);
});
return thisB;
}
// 获取需要被增强的字段
public List<Field> getFieldsToEnrich() {
return Util.allFields(getClass())
.stream()
.filter(field -> !field.isSynthetic())
.filter(field -> !Objects.equals(field.getName(), "capabilities"))
.filter(field -> !Objects.equals(field.getName(), "thisB"))
.filter(field -> !field.getType().isPrimitive())
.filter(field -> !field.getType().isEnum())
.collect(Collectors.toList());
}
}
// 对Feign接口进行自定义的Bean
@FunctionalInterface
public interface FeignBuilderCustomizer {
void customize(Feign.Builder builder);
}
// Feign客户端的配置类
public interface FeignClientConfigurer {
// 标注的@FeignClient是否是主要的@Bean,因为在存在熔断的时候,FeignClient可能存在兜底同类型的Bean,因此,默认将@FeignClent标注的接口作为主要的Bean
// 可以通过该配置进行修改
default boolean primary() {
return true;
}
// 对于每一个FeignClient,都有一个独立的ApplicationContext对象,会继承(父容器)全局的ApplicationContext
// 如果不想继承全局容器中的Bean信息,可以关闭
default boolean inheritParentConfiguration() {
return true;
}
}
// Feign的日志组件,具体依赖的还是对应的日志实现(Slf4j...)
// 在Feign中,日志都是有该对象打印
public abstract class Logger {
protected abstract void log(String configKey, String format, Object... args);
protected boolean shouldLogRequestHeader(String header) {
return true;
}
protected boolean shouldLogResponseHeader(String header) {
return true;
}
// 日志级别,对于每一个FeignClient,都会存在一个Logger对象,并且,Logger对象的日志级别会从Spring容器中获取Level的Bean对象它的日志级别
// 默认为NONE,因为,如果要设置FeignClient的日志级别,可以注入Level的Bean对象
// 还有其他方式,可以使用配置文件属性
public enum Level {
// 不记录日志
NONE,
// 只记录请求方法和URL以及响应状态代码和执行时间
BASIC,
// 记录基本信息以及请求和响应头。
HEADERS,
// 记录请求和响应的报头、正文和元数据。
FULL
}
}
// 重试机制接口
public interface Retryer extends Cloneable {
// 继续执行
void continueOrPropagate(RetryableException e);
// 拷贝属性
Retryer clone();
// 默认实现,就是记录重试次数,不执行业务逻辑,需要自己控制业务逻辑的重试
class Default implements Retryer {
// 重试的最大次数(包括第一次)
private final int maxAttempts;
// 多久之后开启重试机制
private final long period;
// 每隔多久重试一次
private final long maxPeriod;
// 已执行次数
int attempt;
// 重试过程的休眠时间
long sleptForMillis;
// 100ms之后开启重试机制,每隔1秒重试一次,总共执行5次(1(默认调用) + n-1(重试次数))
public Default() {
this(100, SECONDS.toMillis(1), 5);
}
public Default(long period, long maxPeriod, int maxAttempts) {
this.period = period;
this.maxPeriod = maxPeriod;
this.maxAttempts = maxAttempts;
this.attempt = 1;
}
// 可用于测试
protected long currentTimeMillis() {
return System.currentTimeMillis();
}
// 继续重试
public void continueOrPropagate(RetryableException e) {
// 已执行次数大于等于最大执行次数,抛出异常
if (attempt++ >= maxAttempts) {
throw e;
}
// 记录重试次数
long interval;
// 存在下一次的执行时间
if (e.retryAfter() != null) {
// 记录时间间隔
interval = e.retryAfter().getTime() - currentTimeMillis();
if (interval > maxPeriod) {
interval = maxPeriod;
}
if (interval < 0) {
return;
}
} else {
interval = nextMaxInterval();
}
try {
// 休眠到执行的时间间隔再执行
Thread.sleep(interval);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
throw e;
}
// 记录休眠时间
sleptForMillis += interval;
}
// 计算下一次的执行时间间隔
public long nextMaxInterval() {
long interval = (long) (period * Math.pow(1.5, attempt - 1));
return interval > maxPeriod ? maxPeriod : interval;
}
@Override
public Retryer clone() {
return new Default(period, maxPeriod, maxAttempts);
}
}
// 禁止重试机制
Retryer NEVER_RETRY = new Retryer() {
@Override
public void continueOrPropagate(RetryableException e) {
throw e;
}
@Override
public Retryer clone() {
return this;
}
};
}
// 错误解码器,就是处理错误的响应结果的处理器(例如处理404,400)
// 也就是如何返回指定的异常通知下一步需要做什么,例如: 抛出RetryableException表示继续发起重试
public interface ErrorDecoder {
// 方法签名,响应对象
public Exception decode(String methodKey, Response response);
// 默认的实现
public class Default implements ErrorDecoder {
// 重试之后的解码器
private final RetryAfterDecoder retryAfterDecoder = new RetryAfterDecoder();
// 响应体的最大字节长度
private Integer maxBodyBytesLength;
// 响应体的最大字符
private Integer maxBodyCharsLength;
public Default() {
this.maxBodyBytesLength = null;
this.maxBodyCharsLength = null;
}
public Default(Integer maxBodyBytesLength, Integer maxBodyCharsLength) {
this.maxBodyBytesLength = maxBodyBytesLength;
this.maxBodyCharsLength = maxBodyCharsLength;
}
@Override
public Exception decode(String methodKey, Response response) {
// 根据不同的错误状态码进行相应的处理,返回一个FeignException对象
FeignException exception = errorStatus(methodKey, response, maxBodyBytesLength, maxBodyCharsLength);
// 从请求头获取下一次重试的时间
Date retryAfter = retryAfterDecoder.apply(firstOrNull(response.headers(), RETRY_AFTER));
// 如果需要重试,抛出重试异常,这样就会继续发起重试
if (retryAfter != null) {
return new RetryableException(response.status(), exception.getMessage(), response.request().httpMethod(), exception, retryAfter, response.request());
}
// 如果重试完成,则抛出FeignException
return exception;
}
}
// 下次一重试时间的解码器
static class RetryAfterDecoder {
static final DateFormat RFC822_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", US);
private final DateFormat rfc822Format;
RetryAfterDecoder() {
this(RFC822_FORMAT);
}
RetryAfterDecoder(DateFormat rfc822Format) {
this.rfc822Format = checkNotNull(rfc822Format, "rfc822Format");
}
protected long currentTimeMillis() {
return System.currentTimeMillis();
}
// 获取下一次的重试时间
public Date apply(String retryAfter) {
if (retryAfter == null) {
return null;
}
if (retryAfter.matches("^[0-9]+\\.?0*$")) {
retryAfter = retryAfter.replaceAll("\\.0*$", "");
long deltaMillis = SECONDS.toMillis(Long.parseLong(retryAfter));
return new Date(currentTimeMillis() + deltaMillis);
}
return rfc822Format.parse(retryAfter);
}
}
}
// 创建ErrorDecoder的工厂类
public interface FeignErrorDecoderFactory {
ErrorDecoder create(Class<?> type);
}
// Feign发送请求的核心对象
public class Request {
// 请求方式
private final HttpMethod httpMethod;
// 请求url
private final String url;
// 请求头
private final Map<String, Collection<String>> headers;
// 请求体
private final Body body;
// 发送请求的模板对象,它负责组装url,请求参数,请求头等一系列请求相关的数据,所以才成为请求模板类
private final RequestTemplate requestTemplate;
// 请求协议
private final ProtocolVersion protocolVersion;
// 请求方法
public enum HttpMethod {
GET, HEAD, POST(true), PUT(true), DELETE, CONNECT, OPTIONS, TRACE, PATCH(true);
private final boolean withBody;
}
// 创建Request对象
public static Request create(HttpMethod httpMethod, String url, Map<String, Collection<String>> headers, Body body, RequestTemplate requestTemplate) {
return new Request(httpMethod, url, headers, body, requestTemplate);
}
// 请求的属性配置
public static class Options {
private final long connectTimeout;
private final TimeUnit connectTimeoutUnit;
private final long readTimeout;
private final TimeUnit readTimeoutUnit;
private final boolean followRedirects;
}
public static class Body implements Serializable {
private transient Charset encoding;
private byte[] data;
}
}
// 请求拦截器,可以对请求数据进行加工
public interface RequestInterceptor {
// 每个请求都会被调用
void apply(RequestTemplate template);
// Basic认证拦截器,添加Basic请求头
public class BasicAuthRequestInterceptor implements RequestInterceptor {
// 请求头的值
private final String headerValue;
public BasicAuthRequestInterceptor(String username, String password) {
this(username, password, ISO_8859_1);
}
@Override
public void apply(RequestTemplate template) {
template.header("Authorization", headerValue);
}
}
}
// 响应拦截器,同时进行解码操作,具体的操作依赖于解码器
public interface ResponseInterceptor {
// 默认的实现
ResponseInterceptor DEFAULT = (invocationContext) -> {
invocationContext.proceed()
}
// 解码操作
Object aroundDecode(InvocationContext invocationContext) throws IOException;
}
// 执行的上下文对象
public class InvocationContext {
// 解码器
private final Decoder decoder;
// 返回值类型
private final Type returnType;
// 响应体
private final Response response;
public Object proceed() {
// 调用解码器进行解码
return decoder.decode(response, returnType);
}
}
// 将请求参数对象转换为map,然后通过query参数发送请求
public interface QueryMapEncoder {
Map<String, Object> encode(Object object);
public class Default extends FieldQueryMapEncoder {
}
public class FieldQueryMapEncoder implements QueryMapEncoder {
private final Map<Class<?>, ObjectParamMetadata> classToMetadata = new ConcurrentHashMap<>();
@Override
public Map<String, Object> encode(Object object) throws EncodeException {
if (object == null) {
return Collections.emptyMap();
}
// 对象所有字段的元信息,也就是获取该对象的所有字段信息
ObjectParamMetadata metadata = classToMetadata.computeIfAbsent(object.getClass(), ObjectParamMetadata::parseObjectType);
return metadata.objectFields.stream()
// 将字段封装成映射关系 Field -> Optional.ofNullable(FieldValue)
.map(field -> this.FieldValuePair(object, field))
.filter(fieldObjectPair -> fieldObjectPair.right.isPresent())
// 转换为map信息
.collect(Collectors.toMap(
// 优先获取@Param参数的字段名,不存在则获取字段名
this::fieldName,
// 值为该字段的值
fieldObjectPair -> fieldObjectPair.right.get()));
}
// 优先获取@Param参数的字段名,不存在则获取字段名
private String fieldName(Pair<Field, Optional<Object>> pair) {
Param alias = pair.left.getAnnotation(Param.class);
return alias != null ? alias.value() : pair.left.getName();
}
// 对象所有字段的元信息
private static class ObjectParamMetadata {
// 该对象的所有字段
private final List<Field> objectFields;
private ObjectParamMetadata(List<Field> objectFields) {
this.objectFields = Collections.unmodifiableList(objectFields);
}
private static ObjectParamMetadata parseObjectType(Class<?> type) {
List<Field> allFields = new ArrayList();
// 保存该类已经所有父类的所有字段信息
for (Class currentClass = type; currentClass != null; currentClass = currentClass.getSuperclass()) {
Collections.addAll(allFields, currentClass.getDeclaredFields());
}
return new ObjectParamMetadata(allFields.stream()
.filter(field -> !field.isSynthetic())
.peek(field -> field.setAccessible(true))
.collect(Collectors.toList()));
}
}
}
}
// 异常传播策略,在请求过程中出现异常该如何处理
public class ExceptionPropagationPolicy {
NONE,UNWRAP
// 使用该元素的伪代码
public void invoke() {
try {
// 执行请求
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
// 重试
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
// 如果不需要包装异常,则返回抛出的异常类型
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
} else {
// 默认返回包装的RetryableException
throw th;
}
}
}
}
}
// 对Feign组件的增强器
public interface Capability {
// 只选几个显示,增强发送请求的客户端
default Client enrich(Client client) {
return client;
}
// 增强重试机制
default Retryer enrich(Retryer retryer) {
return retryer;
}
// 增强编码器
default Encoder enrich(Encoder encoder) {
return encoder;
}
// 增强解码器
default Decoder enrich(Decoder decoder) {
return decoder;
}
// 缓存的增强器,对目标方法进行缓存逻辑
public class CachingCapability implements Capability {
// Spring的缓存拦截器
private final CacheInterceptor cacheInterceptor;
public CachingCapability(CacheInterceptor cacheInterceptor) {
this.cacheInterceptor = cacheInterceptor;
}
// 对生成JDK代理对象的InvocationHandler进行增强
@Override
public InvocationHandlerFactory enrich(InvocationHandlerFactory invocationHandlerFactory) {
return new FeignCachingInvocationHandlerFactory(invocationHandlerFactory, cacheInterceptor);
}
}
}
// 编码器,将参数编码为请求体的类
public interface Encoder {
// 通配符标识
Type MAP_STRING_WILDCARD = Util.MAP_STRING_WILDCARD;
// 编码
void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException;
// 默认的实现,只支持String和byte[]的编码
public class Default implements Encoder {
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) {
// 如果请求体类型为String
if (bodyType == String.class) {
// 设置String类型的请求体
template.body(object.toString());
}
// byte数组
else if (bodyType == byte[].class) {
template.body((byte[]) object, null);
}
// 如果不是上面两种,抛出异常,默认的编码器只支持这两种
else if (object != null) {
throw new EncodeException(format("%s is not a type supported by this encoder.", object.getClass()));
}
}
}
// 基于Spring的实现
public class SpringEncoder implements Encoder {
// Spring表单的编码器
private final SpringFormEncoder springFormEncoder;
// Spring的消息转换器,将请求和响应数据进行读取和写入的核心类
private final ObjectFactory<HttpMessageConverters> messageConverters;
// Feign编码相关的配置信息
private final FeignEncoderProperties encoderProperties;
// 对HttpMessageConverters进行自定义的类
private final ObjectProvider<HttpMessageConverterCustomizer> customizers;
public SpringEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
this(new SpringFormEncoder(), messageConverters, new FeignEncoderProperties(), new EmptyObjectProvider<>());
}
public SpringEncoder(SpringFormEncoder springFormEncoder, ObjectFactory<HttpMessageConverters> messageConverters, FeignEncoderProperties encoderProperties, ObjectProvider<HttpMessageConverterCustomizer> customizers) {
this.springFormEncoder = springFormEncoder;
this.messageConverters = messageConverters;
this.encoderProperties = encoderProperties;
this.customizers = customizers;
}
@Override
public void encode(Object requestBody, Type bodyType, RequestTemplate request) throws EncodeException {
// template.body(conversionService.convert(object, String.class));
if (requestBody != null) {
// 获取请求头,获取请求体类型
Collection<String> contentTypes = request.headers().get(HttpEncoding.CONTENT_TYPE);
MediaType requestContentType = null;
if (contentTypes != null && !contentTypes.isEmpty()) {
String type = contentTypes.iterator().next();
requestContentType = MediaType.valueOf(type);
}
// 是否是表单类型的请求体
if (isFormRelatedContentType(requestContentType)) {
// 使用表单的编码器进行编码,解析文件,字段等等
springFormEncoder.encode(requestBody, bodyType, request);
return;
}
// 使用消息转换器进行编码
this.encodeWithMessageConverter(requestBody, bodyType, request, requestContentType);
}
}
// 使用消息转换器进行编码
private void encodeWithMessageConverter(Object requestBody, Type bodyType, RequestTemplate request, MediaType requestContentType) {
// 获取所有消息转换器
List<HttpMessageConverter<?>> converters = messageConverters.getObject().getConverters();
// 先执行所有的自定义类
customizers.forEach(customizer -> customizer.accept(converters));
// 遍历所有的消息转换器
for (HttpMessageConverter messageConverter : converters) {
// 判断是否支持写入该类型的数据,如果支持,则写入
FeignOutputMessage outputMessage = checkAndWrite(requestBody, requestContentType, messageConverter, request);
// 如果不为空,表示支持写入
if (outputMessage != null) {
// 请求请求头
request.headers(null);
// 添加新的请求头
request.headers(new LinkedHashMap<>(outputMessage.getHeaders()));
// ... 其他操作
// 最终将数据转换为字节数组传递
request.body(outputMessage.getOutputStream().toByteArray(), charset);
return;
}
}
// 如果没有消息转换器可以写入,抛出异常
throw new EncodeException(message);
}
@SuppressWarnings("unchecked")
private FeignOutputMessage checkAndWrite(Object body, MediaType contentType, HttpMessageConverter converter, RequestTemplate request) throws IOException {
// 判断是否支持写该类型的数据
if (!converter.canWrite(body.getClass(), contentType)) {
return null;
}
// 打印写之前的日志
logBeforeWrite(body, contentType, converter);
FeignOutputMessage outputMessage = new FeignOutputMessage(request);
// 开始写入
converter.write(body, contentType, outputMessage);
return outputMessage;
}
}
}
// 解码器,将响应体解码为返回值的类
public interface Decoder {
Object decode(Response response, Type type) throws IOException, DecodeException, FeignException;
// 默认实现,支持字节数组和String类型的解码
public class Default extends StringDecoder {
@Override
public Object decode(Response response, Type type) throws IOException {
// 非正常状态,返回空对象
if (response.status() == 404 || response.status() == 204) {
return Util.emptyValueOf(type);
}
// 没有响应体,不需要解码
if (response.body() == null) {
return null;
}
// 如果是字符数组,转换为字符数据
if (byte[].class.equals(type)) {
return Util.toByteArray(response.body().asInputStream());
}
// 转换为String
return super.decode(response, type);
}
}
// 将响应体转换为String的解码器
public class StringDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) throws IOException {
// 获取响应体
Response.Body body = response.body();
// 非正常状态,不处理
if (response.status() == 404 || response.status() == 204 || body == null) {
return null;
}
// 将响应体转为String类型
if (String.class.equals(type)) {
return Util.toString(body.asReader(Util.UTF_8));
}
// 不是String类型,抛出异常
throw new DecodeException(response.status(), format("%s is not a type supported by this decoder.", type), response.request());
}
}
// 基于Spring的实现
public class SpringDecoder implements Decoder {
// Spring的消息转换器,将请求和响应数据进行读取和写入的核心类
private final ObjectFactory<HttpMessageConverters> messageConverters;
// 对HttpMessageConverters进行自定义的类
private final ObjectProvider<HttpMessageConverterCustomizer> customizers;
public SpringDecoder(ObjectFactory<HttpMessageConverters> messageConverters, ObjectProvider<HttpMessageConverterCustomizer> customizers) {
this.messageConverters = messageConverters;
this.customizers = customizers;
}
@Override
public Object decode(final Response response, Type type) throws IOException, FeignException {
// 处理任意类或者通配符或者泛型参数
if (type instanceof Class || type instanceof ParameterizedType || type instanceof WildcardType) {
// 获取所有的消息转换器
List<HttpMessageConverter<?>> converters = messageConverters.getObject().getConverters();
// 先执行所有的自定义类
customizers.forEach(customizer -> customizer.accept(converters));
// 创建包装类
IntrospectingClientHttpResponse responseWrapper = new IntrospectingClientHttpResponse(new FeignResponseAdapter(response));
// 如果没有响应体,不需要解码
if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
return null;
}
// 获取响应体类型
MediaType contentType = getContentType(responseWrapper);
// 遍历所有的消息转换器
for (HttpMessageConverter<?> messageConverter : converters) {
if (messageConverter instanceof GenericHttpMessageConverter genericMessageConverter) {
// 判断消息转换器是否可以读取响应体的内容,如果可以读取,就读取成指定的返回值类型
if (genericMessageConverter.canRead(this.responseType, null, contentType)) {
return (T) genericMessageConverter.read(this.responseType, null, responseWrapper);
}
}
}
// 没有消息转换器可以读取该消息,抛出异常
throw new UnknownContentTypeException(this.responseType, contentType, responseWrapper.getStatusCode(), responseWrapper.getStatusText(), responseWrapper.getHeaders(), getResponseBody(responseWrapper));
}
// 不支持的类型
throw new DecodeException(response.status(), "type is not an instance of Class or ParameterizedType: " + type, response.request());
}
}
}
// 参数标注注解
@Target({PARAMETER, FIELD, METHOD})
public @interface Param {
// 参数名称
String value() default "";
// 参数扩展器,因为最终参数都需要转换为String或者byte[],然后在发送请求
// 所以需要一个扩展器,将参数转换为String
Class<? extends Expander> expander() default ToStringExpander.class;
boolean encoded() default false;
// 参数扩展器,因为最终参数都需要转换为String或者byte[],然后在发送请求
// 所以需要一个扩展器,将参数转换为String
interface Expander {
// 将参数转换为String
String expand(Object value);
}
public class ToStringExpander implements Expander {
@Override
public String expand(Object value) {
return value.toString();
}
}
}
// 用于解析类中的所有方法的元数据信息,包括类注解,方法注解,参数注解
public interface Contract {
// 解析指定类的所有方法元数据,并对方法或者参数进行一些校验
List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType);
// 该类就是验证参数的是否符合规则,并且保存各个参数的细节信息,例如该参数是否为URI类型,是否为HeaderMap,获取QueryMap参数,都会记录都方法的元数据对象中
// 具体处理类中,方法中,参数的注解的逻辑都是抽象的
abstract class BaseContract implements Contract {
@Override
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
// 参数校验
// 该类不能存在泛型
checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s", targetType.getSimpleName());
// 该类最多继承或实现一个接口
checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s", targetType.getSimpleName());
// 最终解析到该类对应的所有方法的元数据信息
final Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
// 遍历指定类的所有方法
for (final Method method : targetType.getMethods()) {
// 忽略Object中的方法,以及static方法,以及接口的默认方法
if (method.getDeclaringClass() == Object.class || (method.getModifiers() & Modifier.STATIC) != 0 || Util.isDefault(method)) {
continue;
}
// 解析类中指定方法的元数据
final MethodMetadata metadata = this.parseAndValidateMetadata(targetType, method);
// 如果已经解析过,并且返回值类型不一样,覆盖原来的
if (result.containsKey(metadata.configKey())) {
MethodMetadata existingMetadata = result.get(metadata.configKey());
Type existingReturnType = existingMetadata.returnType();
Type overridingReturnType = metadata.returnType();
Type resolvedType = Types.resolveReturnType(existingReturnType, overridingReturnType);
if (resolvedType.equals(overridingReturnType)) {
result.put(metadata.configKey(), metadata);
}
continue;
}
// 保存该方法的元数据
result.put(metadata.configKey(), metadata);
}
return new ArrayList<>(result.values());
}
// 解析每一个方法元数据
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
// 方法的元数据对象
final MethodMetadata data = new MethodMetadata();
// 设置目标类型
data.targetType(targetType);
// 设置方法对象
data.method(method);
// 设置方法的返回类型
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
// 设置方法签名
data.configKey(Feign.configKey(targetType, method));
// 设置是否总是编码请求体
if (AlwaysEncodeBodyContract.class.isAssignableFrom(this.getClass())) {
data.alwaysEncodeBody(true);
}
// 是否存在实现或者继承的接口
if (targetType.getInterfaces().length == 1) {
// 处理接口中的注解
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
// 再处理类中的注解
processAnnotationOnClass(data, targetType);
// 获取方法中的所有注解
for (final Annotation methodAnnotation : method.getAnnotations()) {
// 处理方法中的注解
processAnnotationOnMethod(data, methodAnnotation, method);
}
// 如果标记了忽略该方法,则直接返回,否在继续处理方法参数
if (data.isIgnored()) {
return data;
}
// 如果方法没有标注请求方式,例如@GetMapping等等,抛出异常
checkState(data.template().method() != null, "Method %s not annotated with HTTP method type (ex. GET, POST)%s", data.configKey(), data.warnings());
// 获取方法的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 获取方法的泛型参数类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
// 获取方法的参数注解
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
int count = parameterAnnotations.length;
// 遍历所有的参数注解
for (int i = 0; i < count; i++) {
// 是否是http相关注解,例如: @RequestParam,@PathVariable,@CookieValue等等
boolean isHttpAnnotation = false;
// 如果存在注解信息
if (parameterAnnotations[i] != null) {
// 处理参数中的注解,返回是否是Http注解的标识
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
}
// 如果是http注解
if (isHttpAnnotation) {
// 设置该参数需要被忽略
data.ignoreParamater(i);
}
// 如果参数类型为URI
if (parameterTypes[i] == URI.class) {
// 设置该参数下标为存储的是URI
data.urlIndex(i);
}
// 如果不是Http相关注解,并且不是请求相关参数配置
else if (!isHttpAnnotation && !Request.Options.class.isAssignableFrom(parameterTypes[i])) {
// 如果该参数被处理过
if (data.isAlreadyProcessed(i)) {
// 校验没有表单参数,并且没有标注请求体参数,如果有,抛出异常
checkState(data.formParams().isEmpty() || data.bodyIndex() == null, "Body parameters cannot be used with form parameters.%s", data.warnings());
}
// 如果未标记总是需要编码请求体,将指定参数编码为请求体
else if (!data.alwaysEncodeBody()) {
// 校验没有表单参数,并且没有标注请求体参数,如果有,抛出异常
checkState(data.formParams().isEmpty(), "Body parameters cannot be used with form parameters.%s", data.warnings());
checkState(data.bodyIndex() == null, "Method has too many Body parameters: %s%s", method, data.warnings());
// 标记该参数下标存储的是一个body参数
data.bodyIndex(i);
data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
}
}
}
// 如果方法元数据已经保存了参数为Map,并且为请求头的索引下标
if (data.headerMapIndex() != null) {
// 验证参数的Key
if (Map.class.isAssignableFrom(parameterTypes[data.headerMapIndex()])) {
checkMapKeys("HeaderMap", genericParameterTypes[data.headerMapIndex()]);
}
}
// 如果方法元数据已经保存了参数为Map,并且为查询参数的索引下标
if (data.queryMapIndex() != null) {
if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {
// 验证参数的Key
checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);
}
}
return data;
}
// 解析类中的注解信息
protected abstract void processAnnotationOnClass(MethodMetadata data, Class<?> clz);
// 解析方法中的注解信息
protected abstract void processAnnotationOnMethod(MethodMetadata data, Annotation annotation, Method method);
// 解析参数中的注解信息
protected abstract boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex);
/**
* 保存所有的参数名称, 参数索引 -> 参数名称的映射关系,保存到方法元数据中
*
* @param data 方法的元数据对象
* @param name 方法参数名
* @param index 方法参数的下标
*/
protected void nameParam(MethodMetadata data, String name, int index) {
Collection<String> names = data.indexToName().containsKey(index) ? data.indexToName().get(index) : new ArrayList<String>();
names.add(name);
data.indexToName().put(i, names);
}
}
// Feign默认的方法注解实现
class Default extends DeclarativeContract {
// @RequestLine的正则
// @RequestLine("GET /api/resource?ids={ids}")
static final Pattern REQUEST_LINE_PATTERN = Pattern.compile("^([A-Z]+)[ ]*(.*)$");
public Default() {
// 注册标注在类中的@Headers注解的处理器
super.registerClassAnnotation(Headers.class,
// @Headers注解的处理逻辑
(header, data) -> {
// 获取到注解值
String[] headersOnType = header.value();
// 转换为Map
Map<String, Collection<String>> headers = toMap(headersOnType);
// 保存原有的header
headers.putAll(data.template().headers());
// 清空所有的header
data.template().headers(null);
// 将注解中的header+原有的header组合设置到请求模版对象中
data.template().headers(headers);
});
// 注册标注在方法中的@RequestLine注解的处理器
super.registerMethodAnnotation(RequestLine.class,
// 该@RequestLine注解的处理器
(ann, data) -> {
// 获取注解值
String requestLine = ann.value();
// 获取匹配器
Matcher requestLineMatcher = REQUEST_LINE_PATTERN.matcher(requestLine);
// @RequestLine("GET /api/resource?ids={ids}")
// 不符合规则,抛出异常
if (!requestLineMatcher.find()) {
throw new IllegalStateException(String.format("RequestLine annotation didn't start with an HTTP verb on method %s", data.configKey()));
} else {
// 设置方法的请求方式
data.template().method(HttpMethod.valueOf(requestLineMatcher.group(1)));
// 设置方法的请求路径
data.template().uri(requestLineMatcher.group(2));
}
// 设置其他的
data.template().decodeSlash(ann.decodeSlash());
data.template().collectionFormat(ann.collectionFormat());
});
// 注册标注在方法中的@Body注解的处理器
super.registerMethodAnnotation(Body.class,
(ann, data) -> {
// 获取body
String body = ann.value();
checkState(emptyToNull(body) != null, "Body annotation was empty on method %s.", data.configKey());
// 设置body到请求模版对象中,如果存在{},则要解析模版
if (body.indexOf('{') == -1) {
data.template().body(body);
} else {
data.template().bodyTemplate(body);
}
});
// 注册标注在方法中的@Headers注解的处理器
super.registerMethodAnnotation(Headers.class,
(header, data) -> {
// 获取header的值
String[] headersOnMethod = header.value();
// 直接将header转换为map,设置到请求模板中
data.template().headers(toMap(headersOnMethod));
});
// 注册标注在参数中的@Param注解的处理器
super.registerParameterAnnotation(Param.class,
(paramAnnotation, data, paramIndex) -> {
// 获取注解标注的参数名称
String annotationName = paramAnnotation.value();
// 获取参数对象
Parameter parameter = data.method().getParameters()[paramIndex];
String name;
// 解析名称,优先取注解中的名称,再去参数本身的名称
if (emptyToNull(annotationName) == null && parameter.isNamePresent()) {
name = parameter.getName();
} else {
name = annotationName;
}
// 保存参数名称, 参数索引 -> 参数名称的映射关系,保存到方法元数据中
this.nameParam(data, name, paramIndex);
// 获取展开器,将指定值转换为String类型的类
Class<? extends Param.Expander> expander = paramAnnotation.expander();
// 如果不是ToStringExpander展开器
if (expander != Param.ToStringExpander.class) {
// 保存该参数的下标以及将该参数转为String类型的展开器的映射关系
data.indexToExpanderClass().put(paramIndex, expander);
}
// 如果url变量,请求头,请求参数中包含该名称
if (!data.template().hasRequestVariable(name)) {
// 将该名称添加到表单参数中
data.formParams().add(name);
}
});
// 注册标注在参数中的@QueryMap注解的处理器
super.registerParameterAnnotation(QueryMap.class,
(queryMap, data, paramIndex) -> {
// 将该参数设置为是一个queryMap,最终会将它设置到query参数中
data.queryMapIndex(paramIndex);
});
// 注册标注在参数中的@HeaderMap注解的处理器
super.registerParameterAnnotation(HeaderMap.class,
(queryMap, data, paramIndex) -> {
// 将该参数设置为是一个headerMap,最终会将它设置到请求头中
data.headerMapIndex(paramIndex);
});
}
}
// 声明式的类方法处理器,根据类中注解,方法中的注解,参数中的注解进行处理
public abstract class DeclarativeContract extends BaseContract {
// 处理类中注解的处理器
private final List<GuardedAnnotationProcessor> classAnnotationProcessors = new ArrayList<>();
// 处理方法中注解的处理器
private final List<GuardedAnnotationProcessor> methodAnnotationProcessors = new ArrayList<>();
// 处理参数注解的处理器
private final Map<Class<Annotation>, DeclarativeContract.ParameterAnnotationProcessor<Annotation>> parameterAnnotationProcessors = new HashMap<>();
@Override
public final List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
// any implementations must register processors
return super.parseAndValidateMetadata(targetType);
}
// 处理类中的注解
@Override
protected final void processAnnotationOnClass(MethodMetadata data, Class<?> targetType) {
// 获取类中的所有的注解信息
final List<GuardedAnnotationProcessor> processors = Arrays.stream(targetType.getAnnotations())
// 遍历每一个注解,并且找到类处理器中能处理该注解的所有处理器
.flatMap(annotation -> classAnnotationProcessors.stream()
.filter(processor -> processor.test(annotation)))
// 将符合条件的所有类注解处理器保存
.collect(Collectors.toList());
// 如果存在可以处理类中注解的处理器
if (!processors.isEmpty()) {
// 执行可以处理这些注解的处理器,解析类注解
Arrays.stream(targetType.getAnnotations())
.forEach(annotation -> processors.stream()
.filter(processor -> processor.test(annotation))
.forEach(processor -> processor.process(annotation, data)));
}
// 不存在任何类注解相关的处理器
else {
// 记录警告信息
if (targetType.getAnnotations().length == 0) {
data.addWarning(String.format("Class %s has no annotations, it may affect contract %s", targetType.getSimpleName(), getClass().getSimpleName()));
} else {
data.addWarning(String.format("Class %s has annotations %s that are not used by contract %s", targetType.getSimpleName(), Arrays.stream(targetType.getAnnotations()).map(annotation -> annotation.annotationType().getSimpleName()).collect(Collectors.toList()), getClass().getSimpleName()));
}
}
}
// 处理方法中的注解信息
@Override
protected final void processAnnotationOnMethod(MethodMetadata data, Annotation annotation, Method method) {
// 遍历所有的方法处理器
List<GuardedAnnotationProcessor> processors = methodAnnotationProcessors.stream()
// 过滤处能处理该注解的所有处理器
.filter(processor -> processor.test(annotation))
.collect(Collectors.toList());
// 如果存在能处理该注解的处理器
if (!processors.isEmpty()) {
// 执行处理器,解析方法注解
processors.forEach(processor -> processor.process(annotation, data));
}
// 如果没有任何处理器,记录警告信息
else {
data.addWarning(String.format("Method %s has an annotation %s that is not used by contract %s", method.getName(), annotation.annotationType().getSimpleName(), getClass().getSimpleName()));
}
}
// 处理参数中的注解
@Override
protected final boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
// 遍历所有方法的注解
List<Annotation> matchingAnnotations = Arrays.stream(annotations)
// 过滤存在处理器这些注解
.filter(annotation -> parameterAnnotationProcessors.containsKey(annotation.annotationType()))
.collect(Collectors.toList());
// 如果有注解存在处理器
if (!matchingAnnotations.isEmpty()) {
// 获取该注解对应的处理器,执行该处理器,执行参数注解解析逻辑
matchingAnnotations.forEach(annotation -> parameterAnnotationProcessors
.getOrDefault(annotation.annotationType(), ParameterAnnotationProcessor.DO_NOTHING)
.process(annotation, data, paramIndex));
}
// 如果没有任何注解存在对应的处理器
else {
// 获取到该下标的参数对象
Parameter parameter = data.method().getParameters()[paramIndex];
// 获取参数名
String parameterName = parameter.isNamePresent() ? parameter.getName() : parameter.getType().getSimpleName();
// 记录参数的警告信息
if (annotations.length == 0) {
data.addWarning(String.format("Parameter %s has no annotations, it may affect contract %s", parameterName, getClass().getSimpleName()));
} else {
data.addWarning(String.format("Parameter %s has annotations %s that are not used by contract %s", parameterName, Arrays.stream(annotations).map(annotation -> annotation.annotationType().getSimpleName()).collect(Collectors.toList()), getClass().getSimpleName()));
}
}
// 返回不是处理的http相关的注解信息
return false;
}
// 注册类处理器,带有条件
protected <E extends Annotation> void registerClassAnnotation(Class<E> annotationType, DeclarativeContract.AnnotationProcessor<E> processor) {
this.registerClassAnnotation(annotation -> annotation.annotationType().equals(annotationType), processor);
}
// 注册类处理器,带有条件
protected <E extends Annotation> void registerClassAnnotation(Predicate<E> predicate, DeclarativeContract.AnnotationProcessor<E> processor) {
this.classAnnotationProcessors.add(new GuardedAnnotationProcessor(predicate, processor));
}
// 注册方法处理器
protected <E extends Annotation> void registerMethodAnnotation(Class<E> annotationType, DeclarativeContract.AnnotationProcessor<E> processor) {
this.registerMethodAnnotation(annotation -> annotation.annotationType().equals(annotationType), processor);
}
// 注册方法处理器,带有条件
protected <E extends Annotation> void registerMethodAnnotation(Predicate<E> predicate, DeclarativeContract.AnnotationProcessor<E> processor) {
this.methodAnnotationProcessors.add(new GuardedAnnotationProcessor(predicate, processor));
}
// 注册参数注解处理器
protected <E extends Annotation> void registerParameterAnnotation(Class<E> annotation, DeclarativeContract.ParameterAnnotationProcessor<E> processor) {
this.parameterAnnotationProcessors.put((Class) annotation, (DeclarativeContract.ParameterAnnotationProcessor) processor);
}
// 标注的注解处理器
@FunctionalInterface
public interface AnnotationProcessor<E extends Annotation> {
void process(E annotation, MethodMetadata metadata);
}
// 参数注解处理器
public interface ParameterAnnotationProcessor<E extends Annotation> {
DeclarativeContract.ParameterAnnotationProcessor<Annotation> DO_NOTHING = (ann, data, i) -> {
};
// 处理指定参数的注解
void process(E annotation, MethodMetadata metadata, int paramIndex);
}
// 带有条件的注解处理器,这是一个装饰者模式
private class GuardedAnnotationProcessor implements Predicate<Annotation>, DeclarativeContract.AnnotationProcessor<Annotation> {
// 满足条件,才会执行process方法
private final Predicate<Annotation> predicate;
// 注解处理器,这是一个装饰者模式
private final DeclarativeContract.AnnotationProcessor<Annotation> processor;
private GuardedAnnotationProcessor(Predicate predicate, DeclarativeContract.AnnotationProcessor processor) {
this.predicate = predicate;
this.processor = processor;
}
// 处理指定的注解信息
@Override
public void process(Annotation annotation, MethodMetadata metadata) {
processor.process(annotation, metadata);
}
// 条件判断
@Override
public boolean test(Annotation t) {
return predicate.test(t);
}
}
}
// 用于解析类中的SpringMVC类注解,方法注解,参数注解元数据信息
public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware {
// 注解参数处理器
private final Map<Class<? extends Annotation>, AnnotatedParameterProcessor> annotatedArgumentProcessors;
// 保存正在处理的方法
private final Map<String, Method> processedMethods = new HashMap<>();
// 类型转换器
private final ConversionService conversionService;
/**
* 创建类型转换Expander类的工厂类
* {@link Contract.MethodMetadata#indexToExpander}
*/
private final ConvertingExpanderFactory convertingExpanderFactory;
// 资源加载器
private ResourceLoader resourceLoader = new DefaultResourceLoader();
// 是否解析解码"/"
private final boolean decodeSlash;
public SpringMvcContract() {
this(Collections.emptyList());
}
public SpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors) {
this(annotatedParameterProcessors, new DefaultConversionService());
}
public SpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors, ConversionService conversionService) {
this(annotatedParameterProcessors, conversionService, true);
}
public SpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors, ConversionService conversionService, boolean decodeSlash) {
// 默认的注解参数处理器
List<AnnotatedParameterProcessor> processors = this.getDefaultAnnotatedArgumentsProcessors();
processors.addAll(annotatedParameterProcessors);
// 将所有处理器转换为支持处理注解->该注解处理器的映射关系
this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
this.conversionService = conversionService;
this.convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
this.decodeSlash = decodeSlash;
}
// 处理类注解
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
// 获取类中的RequestMapping注解
RequestMapping classAnnotation = findMergedAnnotation(clz, RequestMapping.class);
// 校验,如果类中存在该注解,抛出异常,@FeignClient不允许标注
if (classAnnotation != null) {
LOG.error("Cannot process class: " + clz.getName() + ". @RequestMapping annotation is not allowed on @FeignClient interfaces.");
throw new IllegalArgumentException("@RequestMapping annotation not allowed on @FeignClient interfaces");
}
// 获取@CollectionFormat注解
CollectionFormat collectionFormat = findMergedAnnotation(clz, CollectionFormat.class);
// 如果存在
if (collectionFormat != null) {
/**
* 设置集合参数的类型转换器,将请求参数按照指定的格式解析为方法参数类型
* 例如:
* <pre>
* @RequestLine("GET /api/resource?ids={ids}")
* void getResource(@Param(value = "ids", collectionFormat = CollectionFormat.CSV) List<String> ids);
* </pre>
*/
// 设置到请求模版对象中
data.template().collectionFormat(collectionFormat.value());
}
}
@Override
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
// 保存一下当前方法信息
processedMethods.put(Feign.configKey(targetType, method), method);
return super.parseAndValidateMetadata(targetType, method);
}
// 处理方法注解
@Override
protected void processAnnotationOnMethod(MethodMetadata data, Annotation methodAnnotation, Method method) {
// 注解是否是CollectionFormat类型
if (methodAnnotation instanceof CollectionFormat) {
/**
* 设置集合参数的类型转换器,将请求参数按照指定的格式解析为方法参数类型
* 例如:
* <pre>
* @RequestLine("GET /api/resource?ids={ids}")
* void getResource(@Param(value = "ids", collectionFormat = CollectionFormat.CSV) List<String> ids);
* </pre>
*/
CollectionFormat collectionFormat = findMergedAnnotation(method, CollectionFormat.class);
data.template().collectionFormat(collectionFormat.value());
}
// 如果方法不是RequestMapping,并且也不是RequestMapping的变种,例如@GetMapping
if (!(methodAnnotation instanceof RequestMapping) && !methodAnnotation.annotationType().isAnnotationPresent(RequestMapping.class)) {
return;
}
// 获取该注解信息
RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
// 获取请求方式
RequestMethod[] methods = methodMapping.method();
// 默认为Get
if (methods.length == 0) {
methods = new RequestMethod[]{RequestMethod.GET};
}
// 给请求模板设置请求方式
data.template().method(Request.HttpMethod.valueOf(methods[0].name()));
// 设置请求路径
if (methodMapping.value().length > 0) {
// 获取请求路径
String pathValue = emptyToNull(methodMapping.value()[0]);
if (pathValue != null) {
// 解析占位符
pathValue = resolve(pathValue);
if (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) {
pathValue = "/" + pathValue;
}
// 该请求模板设置请求路径
data.template().uri(pathValue, true);
// 设置是否支持解码"/"
if (data.template().decodeSlash() != decodeSlash) {
data.template().decodeSlash(decodeSlash);
}
}
}
// 解析RequestMapping的信息,并设置到请求模板对象中
// 解析RequestMapping的produces,服务器提供的媒体类型(服务器响应的媒体类型)
this.parseProduces(data, method, methodMapping);
// 解析RequestMapping的consumes,客户端提供的媒体类型(客户端发送的媒体类型)
this.parseConsumes(data, method, methodMapping);
// 处理RequestMapping的headers响应头
this.parseHeaders(data, method, methodMapping);
// 参数的下标以及将该参数转为String类型的展开器的映射关系
// 和indexToExpanderClass差不多,但是不在是Class,而是该类的实例对象
data.indexToExpander(new LinkedHashMap<>());
}
// 处理参数注解
@Override
protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) {
// 是否是http相关注解
boolean isHttpAnnotation = false;
// Jpa的分页支持
if (Pageable.class.isAssignableFrom(data.method().getParameterTypes()[paramIndex])) {
// 如果方法参数存在@RequestParam,@SpringQueryMap,@QueryMap,获取参数类型为Map,都返回true
if (!this.queryMapParamPresent(data)) {
// 将Pageable类型的参数标记为QueryMap,因为它包含了page和limit,还有排序多个字段
data.queryMapIndex(paramIndex);
// 处理的不是http相关注解
return false;
}
}
// 创建注解处理的上下文对象
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(data, paramIndex);
// 获取方法
Method method = processedMethods.get(data.configKey());
// 遍历所有参数注解
for (Annotation parameterAnnotation : annotations) {
// 获取到能处理该注解的参数处理器
AnnotatedParameterProcessor processor = annotatedArgumentProcessors.get(parameterAnnotation.annotationType());
// 如果存在
if (processor != null) {
Annotation processParameterAnnotation;
// 处理@AliasFor
processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(parameterAnnotation, method, paramIndex);
/**
* 执行该参数处理器,处理该注解信息,例如,处理RequestParam注解
* {@link RequestParamParameterProcessor}
*/
// |= 表示任何一个为true,则为true,false与任何值|都是原来的值
isHttpAnnotation |= processor.processArgument(context, processParameterAnnotation, method);
}
}
// 如果不是文件表单数据
if (!this.isMultipartFormData(data) && isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
// 对该参数进行类型转换
if (conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) {
// 获取参数展开器,将参数转换为String类型
Param.Expander expander = convertingExpanderFactory.getExpander(typeDescriptor);
if (expander != null) {
// 将该参数转换为String类型
data.indexToExpander().put(paramIndex, expander);
}
}
}
return isHttpAnnotation;
}
// 如果方法参数存在@RequestParam,@SpringQueryMap,@QueryMap,获取参数类型为Map,都返回true
private boolean queryMapParamPresent(MethodMetadata data) {
Annotation[][] paramsAnnotations = data.method().getParameterAnnotations();
for (int i = 0; i < paramsAnnotations.length; i++) {
Annotation[] paramAnnotations = paramsAnnotations[i];
Class<?> parameterType = data.method().getParameterTypes()[i];
if (Arrays.stream(paramAnnotations).anyMatch(annotation -> Map.class.isAssignableFrom(parameterType) && annotation instanceof RequestParam || annotation instanceof SpringQueryMap || annotation instanceof QueryMap)) {
return true;
}
}
return false;
}
// 将所有处理器转换为支持处理注解->该注解处理器的映射关系
private Map<Class<? extends Annotation>, AnnotatedParameterProcessor> toAnnotatedArgumentProcessorMap(List<AnnotatedParameterProcessor> processors) {
Map<Class<? extends Annotation>, AnnotatedParameterProcessor> result = new HashMap<>();
for (AnnotatedParameterProcessor processor : processors) {
// 获取该处理器支持处理的注解信息作为Key
result.put(processor.getAnnotationType(), processor);
}
return result;
}
// 默认的参数处理器
private List<AnnotatedParameterProcessor> getDefaultAnnotatedArgumentsProcessors() {
List<AnnotatedParameterProcessor> annotatedArgumentResolvers = new ArrayList<>();
// 处理@MatrixVariable
this.annotatedArgumentResolvers.add(new MatrixVariableParameterProcessor());
// 处理@PathVariable
this.annotatedArgumentResolvers.add(new PathVariableParameterProcessor());
// 处理@RequestParam
this.annotatedArgumentResolvers.add(new RequestParamParameterProcessor());
// 处理@RequestHeader
this.annotatedArgumentResolvers.add(new RequestHeaderParameterProcessor());
// 处理@QueryMap
this.annotatedArgumentResolvers.add(new QueryMapParameterProcessor());
// 处理@RequestPart
this.annotatedArgumentResolvers.add(new RequestPartParameterProcessor());
// 处理@CookieValue
this.annotatedArgumentResolvers.add(new CookieValueParameterProcessor());
return annotatedArgumentResolvers;
}
// 是否是文件表单数据
private boolean isMultipartFormData(MethodMetadata data) {
// 获取ContextType
Collection<String> contentTypes = data.template().headers().get(HttpEncoding.CONTENT_TYPE);
// 如果为MULTIPART_FORM_DATA,表示为文件表单数据
if (contentTypes != null && !contentTypes.isEmpty()) {
String type = contentTypes.iterator().next();
return Objects.equals(MediaType.valueOf(type), MediaType.MULTIPART_FORM_DATA);
}
return false;
}
// 创建类型转换Expander类的工厂类
private static class ConvertingExpanderFactory {
private final ConversionService conversionService;
ConvertingExpanderFactory(ConversionService conversionService) {
this.conversionService = conversionService;
}
// 生成扩展器
Param.Expander getExpander(TypeDescriptor typeDescriptor) {
return value -> {
// 将指定的值转换为Strnig类型
Object converted = conversionService.convert(value, typeDescriptor, STRING_TYPE_DESCRIPTOR);
return (String) converted;
};
}
}
// 处理@RequestParam的处理器
public class RequestParamParameterProcessor implements AnnotatedParameterProcessor {
private static final Class<RequestParam> ANNOTATION = RequestParam.class;
// 支持处理类型
@Override
public Class<? extends Annotation> getAnnotationType() {
return ANNOTATION;
}
// 处理参数
@Override
public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
// 获取参数索引
int parameterIndex = context.getParameterIndex();
// 获取参数类型
Class<?> parameterType = method.getParameterTypes()[parameterIndex];
// 获取方法元数据信息
MethodMetadata data = context.getMethodMetadata();
// 如果参数为Map
if (Map.class.isAssignableFrom(parameterType)) {
// 校验
checkState(data.queryMapIndex() == null, "Query map can only be present once.");
// 标记当前下标参数为query的Map参数
data.queryMapIndex(parameterIndex);
return true;
}
// 强转为注解类型
RequestParam requestParam = ANNOTATION.cast(annotation);
// 获取参数名
String name = requestParam.value();
// 校验不能为空
checkState(emptyToNull(name) != null, "RequestParam.value() was empty on parameter %s", parameterIndex);
// 设置参数名
context.setParameterName(name);
// 将这些参数添加到请求模版对象的query参数中
Collection<String> query = context.setTemplateParameter(name, data.template().queries().get(name));
data.template().query(name, query);
// 处理的http相关注解
return true;
}
}
}
}
// 方法的与数据对象
public final class MethodMetadata implements Serializable {
// 方法的签名
private String configKey;
// 方法的返回类型
private transient Type returnType;
// 方法参数为URI的索引下标
private Integer urlIndex;
// 方法参数需要进行编码为请求体的索引下标
private Integer bodyIndex;
// 参数为Map的并且为请求头的索引下标
private Integer headerMapIndex;
// 参数为Map的并且为query参数的索引下标
private Integer queryMapIndex;
// 该方法是否总是编码请求体
private boolean alwaysEncodeBody;
// 请求体类型
private transient Type bodyType;
// 请求模板对象
private final RequestTemplate template = new RequestTemplate();
// 表单参数
private final List<String> formParams = new ArrayList<String>();
// 参数的下标以及名称的映射关系
private final Map<Integer, Collection<String>> indexToName = new LinkedHashMap<Integer, Collection<String>>();
// 参数的下标以及将该参数转为String类型的展开器的映射关系
private final Map<Integer, Class<? extends Expander>> indexToExpanderClass = new LinkedHashMap<Integer, Class<? extends Expander>>();
// 参数的下标以及将该参数是否需要编码的映射关系
private final Map<Integer, Boolean> indexToEncoded = new LinkedHashMap<Integer, Boolean>();
// 参数的下标以及将该参数转为String类型的展开器的映射关系
// 和indexToExpanderClass差不多,但是不在是Class,而是该类的实例对象
private transient Map<Integer, Expander> indexToExpander;
// 需要忽略的参数下标
private BitSet parameterToIgnore = new BitSet();
// 当前方法是否需要忽略参数处理
private boolean ignored;
// 目标类类型
private transient Class<?> targetType;
// 方法对象
private transient Method method;
// 验证的警告信息
private transient final List<String> warnings = new ArrayList<>();
MethodMetadata() {
template.methodMetadata(this);
}
}
// 发送Http请求的客户端
public interface Client {
/**
* 发送Http请求
*
* @param request 请求对象
* @param options 请求配置信息
* @return 响应对象
*/
Response execute(Request request, Options options) throws IOException;
// 默认的实现
class Default implements Client {
// SSL套接字工厂
private final SSLSocketFactory sslContextFactory;
// 主机验证器
private final HostnameVerifier hostnameVerifier;
// 禁用请求缓冲
private final boolean disableRequestBuffering;
public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier) {
this(sslContextFactory, hostnameVerifier, true);
}
public Default(SSLSocketFactory sslContextFactory, HostnameVerifier hostnameVerifier, boolean disableRequestBuffering) {
this.sslContextFactory = sslContextFactory;
this.hostnameVerifier = hostnameVerifier;
this.disableRequestBuffering = disableRequestBuffering;
}
@Override
public Response execute(Request request, Options options) throws IOException {
// 转换参数并且发送请求
HttpURLConnection connection = this.convertAndSend(request, options);
return this.convertResponse(connection, request);
}
public Response convertResponse(HttpURLConnection connection, Request request) throws IOException {
// 获取响应码
int status = connection.getResponseCode();
// 获取响应消息
String reason = connection.getResponseMessage();
// 校验状态码
if (status < 0) {
throw new IOException(format("Invalid status(%s) executing %s %s", status, connection.getRequestMethod(), connection.getURL()));
}
//
Map<String, Collection<String>> headers = new TreeMap<>(CASE_INSENSITIVE_ORDER);
// 获取响应头
for (Map.Entry<String, List<String>> field : connection.getHeaderFields().entrySet()) {
if (field.getKey() != null) {
// 保存响应头
headers.put(field.getKey(), field.getValue());
}
}
// 获取内容长度
Integer length = connection.getContentLength();
if (length == -1) {
length = null;
}
// 获取响应体
InputStream stream;
// 异常请求
if (status >= 400) {
// 获取错误的流数据
stream = connection.getErrorStream();
}
// 正常情况
else {
// 如果开启了Gzip
if (this.isGzip(headers.get(CONTENT_ENCODING))) {
// 装饰为GZIP流
stream = new GZIPInputStream(connection.getInputStream());
}
// 如果开启了压缩
else if (this.isDeflate(headers.get(CONTENT_ENCODING))) {
// 装饰为压缩流
stream = new InflaterInputStream(connection.getInputStream());
}
// 没有开启压缩,获取响应体
else {
stream = connection.getInputStream();
}
}
// 返回响应信息
return Response.builder().status(status).reason(reason).headers(headers).request(request).body(stream, length).build();
}
// 转换参数并且发送请求
public HttpURLConnection convertAndSend(Request request, Options options) throws IOException {
// 获取请求的url
final URL url = new URL(request.url());
// 获取URL连接
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 如果为https
if (connection instanceof HttpsURLConnection) {
HttpsURLConnection sslCon = (HttpsURLConnection) connection;
// 设置SSL套接字工厂
if (sslContextFactory != null) {
sslCon.setSSLSocketFactory(sslContextFactory);
}
// 主机验证器
if (hostnameVerifier != null) {
sslCon.setHostnameVerifier(hostnameVerifier);
}
}
// 设置连接时间
connection.setConnectTimeout(options.connectTimeoutMillis());
// 设置请求超时时间
connection.setReadTimeout(options.readTimeoutMillis());
// 设置是否允许用户交互
connection.setAllowUserInteraction(false);
// 设置是否跟随重定向
connection.setInstanceFollowRedirects(options.isFollowRedirects());
// 设置请求方式
connection.setRequestMethod(request.httpMethod().name());
// 获取指定请求头
Collection<String> contentEncodingValues = request.headers().get(CONTENT_ENCODING);
// 是否开启了请求Gzip
boolean gzipEncodedRequest = this.isGzip(contentEncodingValues);
// 是否开启了压缩请求
boolean deflateEncodedRequest = this.isDeflate(contentEncodingValues);
// 是否存在Accept
boolean hasAcceptHeader = false;
// 内容长度
Integer contentLength = null;
// 遍历所有的请求头
for (String field : request.headers().keySet()) {
if (field.equalsIgnoreCase("Accept")) {
hasAcceptHeader = true;
}
// 获取请求头的值
for (String value : request.headers().get(field)) {
// 设置contentLength
if (field.equals(CONTENT_LENGTH)) {
// 如果未开启Gzip或者压缩
if (!gzipEncodedRequest && !deflateEncodedRequest) {
// 设置内容的长度
contentLength = Integer.valueOf(value);
connection.addRequestProperty(field, value);
}
} else {
connection.addRequestProperty(field, value);
}
}
}
// 添加Accept为*/*
if (!hasAcceptHeader) {
connection.addRequestProperty("Accept", "*/*");
}
// 是否为空请求体
boolean hasEmptyBody = false;
// 获取请求体
byte[] body = request.body();
// 如果没有body并且当前请求方式可以携带Body
if (body == null && request.httpMethod().isWithBody()) {
// 设置空body并标记
body = new byte[0];
hasEmptyBody = true;
}
// 如果存在Body
if (body != null) {
// 如果禁用请求缓冲,并且存在Body内容
if (disableRequestBuffering && !hasEmptyBody) {
// 设置内容模式
if (contentLength != null) {
connection.setFixedLengthStreamingMode(contentLength);
} else {
connection.setChunkedStreamingMode(8196);
}
}
connection.setDoOutput(true);
// 获取输出流
OutputStream out = connection.getOutputStream();
// 如果开启Gzip
if (gzipEncodedRequest) {
// 装饰为Gzip流
out = new GZIPOutputStream(out);
}
// 如果开启压缩
else if (deflateEncodedRequest) {
// 装饰为压缩流
out = new DeflaterOutputStream(out);
}
try {
// 将请求体写入流中
out.write(body);
} finally {
// 关闭流
out.close();
}
}
return connection;
}
private boolean isGzip(Collection<String> contentEncodingValues) {
return contentEncodingValues != null && !contentEncodingValues.isEmpty() && contentEncodingValues.contains(ENCODING_GZIP);
}
private boolean isDeflate(Collection<String> contentEncodingValues) {
return contentEncodingValues != null && !contentEncodingValues.isEmpty() && contentEncodingValues.contains(ENCODING_DEFLATE);
}
}
// Feign阻塞的负载均衡客户端
public class FeignBlockingLoadBalancerClient implements Client {
// 实际发送请求的客户端
private final Client delegate;
// 负载均衡客户端,负责选择服务实例
private final LoadBalancerClient loadBalancerClient;
// 生成LoadBalancerClient的工厂
private final LoadBalancerClientFactory loadBalancerClientFactory;
// 对发送的请求对象进行转换的转换类,通过该类可以对Reqeust对象进行加工
private final List<LoadBalancerFeignRequestTransformer> transformers;
@Override
public Response execute(Request request, Request.Options options) throws IOException {
// 获取URL
final URI originalUri = URI.create(request.url());
// 获取主机名
String serviceId = originalUri.getHost();
// 获取提示
String hint = getHint(serviceId);
// 创建默认的负载均衡请求对象,包括请求数据以及请求数据上下文
DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(new RequestDataContext(buildRequestData(request), hint));
// 获取负载均衡的生命周期接口
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator.getSupportedLifecycleProcessors(loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class), RequestDataContext.class, ResponseData.class, ServiceInstance.class);
// 执行这些接口的onStart方法
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
// 选择需要请求的实例
ServiceInstance instance = loadBalancerClient.choose(serviceId, lbRequest);
// 创建默认的响应对象
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse = new DefaultResponse(instance);
// 如果没有获取到服务实例
if (instance == null) {
String message = "Load balancer does not contain an instance for the service " + serviceId;
if (LOG.isWarnEnabled()) {
LOG.warn(message);
}
// 执行生命周期的完成方法
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(CompletionContext.Status.DISCARD, lbRequest, lbResponse)));
// 返回响应对象,响应码为503(服务不可用)
return Response.builder().request(request).status(HttpStatus.SERVICE_UNAVAILABLE.value()).body(message, StandardCharsets.UTF_8).build();
}
// 解析最终请求的URL
String reconstructedUrl = loadBalancerClient.reconstructURI(instance, originalUri).toString();
// 构建最终的请求对象
Request newRequest = this.buildRequest(request, reconstructedUrl, instance);
// 执行生命周期方法,开始发送请求
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
try {
// 发送http请求
Response response = feignClient.execute(feignRequest, options);
// 如果是负载均衡,执行onComplete完成方法的生命周期
if (loadBalanced) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.SUCCESS, lbRequest, lbResponse, buildResponseData(response))));
}
// 返回响应结果
return response;
} catch (Exception exception) {
// 异常结束,也执行完成的生命周期方法
if (loadBalanced) {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.FAILED, exception, lbRequest, lbResponse)));
}
// 抛出异常
throw exception;
}
}
// 创建基础的请求对象
protected Request buildRequest(Request request, String reconstructedUrl) {
return Request.create(request.httpMethod(), reconstructedUrl, request.headers(), request.body(), request.charset(), request.requestTemplate());
}
// 构建请求对象并加工
protected Request buildRequest(Request request, String reconstructedUrl, ServiceInstance instance) {
// 创建基础的请求对象
Request newRequest = this.buildRequest(request, reconstructedUrl);
// 对发送的请求对象进行转换的转换类,通过该类可以对Reqeust对象进行加工
if (transformers != null) {
// 遍历所有的请求对象转换器,对请求进行加工
for (LoadBalancerFeignRequestTransformer transformer : transformers) {
// 返回新的请求对象
newRequest = transformer.transformRequest(newRequest, instance);
}
}
return newRequest;
}
}
}
// 请求模板对象
public final class RequestTemplate implements Serializable {
// 参数正则
// 用于匹配查询字符串中的 ?
private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");
// 请求参数
private final Map<String, QueryTemplate> queries = new LinkedHashMap<>();
// 请求头
private final Map<String, HeaderTemplate> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
// 请求的目标 URL
private String target;
// 请求的片段(Fragment)部分
private String fragment;
// 表示请求模板是否已解析
private boolean resolved = false;
// 请求的 URI 模板
private UriTemplate uriTemplate;
// 请求的消息体模板
private BodyTemplate bodyTemplate;
// 请求方式
private HttpMethod method;
// 字符集
private transient Charset charset = Util.UTF_8;
// 请求体数据
private Request.Body body = Request.Body.empty();
// 是否解码"/"
private boolean decodeSlash = true;
// 按照什么格式将集合类型的参数转换为请求体
private CollectionFormat collectionFormat = CollectionFormat.EXPLODED;
// 方法的元数据对象
private MethodMetadata methodMetadata;
// FeignClinet接口信息
private Target<?> feignTarget;
// 创建RequestTemplate的工厂类
interface Factory {
RequestTemplate create(Object[] argv);
}
// 根据所有请求参数变量解析
public RequestTemplate resolve(Map<String, ?> variables) {
// 最终请求url
StringBuilder uri = new StringBuilder();
// 创建新的请求模板对象
RequestTemplate resolved = RequestTemplate.from(this);
// 如果不存在请求的url模板
if (this.uriTemplate == null) {
// 创建一个uri的模板对象,该对象最终会得到一个可用的url(可能需要进行解码,编码等操作)
this.uriTemplate = UriTemplate.create("", !this.decodeSlash, this.charset);
}
// 扩展url(解析url表达式)
String expanded = this.uriTemplate.expand(variables);
// 保存解析的url
if (expanded != null) {
uri.append(expanded);
}
// 如果存在query参数,进行?,&拼接
if (!this.queries.isEmpty()) {
// 初始化query参数集合
resolved.queries(Collections.emptyMap());
StringBuilder query = new StringBuilder();
// 获取所有的请求参数
Iterator<QueryTemplate> queryTemplates = this.queries.values().iterator();
// 遍历所有的请求参数
while (queryTemplates.hasNext()) {
QueryTemplate queryTemplate = queryTemplates.next();
// 扩展请求参数(解析参数表达式)
String queryExpanded = queryTemplate.expand(variables);
if (Util.isNotBlank(queryExpanded)) {
query.append(queryExpanded);
if (queryTemplates.hasNext()) {
query.append("&");
}
}
}
// 拼接query参数
String queryString = query.toString();
if (!queryString.isEmpty()) {
Matcher queryMatcher = QUERY_STRING_PATTERN.matcher(uri);
if (queryMatcher.find()) {
uri.append("&");
} else {
uri.append("?");
}
uri.append(queryString);
}
}
// 设置解析好的uri
resolved.uri(uri.toString());
// 如果存在请求头
if (!this.headers.isEmpty()) {
// 初始化请求头集合
resolved.headers(Collections.emptyMap());
// 遍历所有请求头
for (HeaderTemplate headerTemplate : this.headers.values()) {
// 扩展请求头(解析请求头表达式)
String header = headerTemplate.expand(variables);
if (!header.isEmpty()) {
// 添加请求头
resolved.appendHeader(headerTemplate.getName(), Collections.singletonList(header), true);
}
}
}
// 如果存在body
if (this.bodyTemplate != null) {
// 扩展body(解析body表达式)
resolved.body(this.bodyTemplate.expand(variables));
}
// 标记该请求模板已被解析
resolved.resolved = true;
return resolved;
}
}
// 负载均衡Feign的请求对象的转换器,在Feign发送请求的时候,在发送之前会执行该操作
@Order(LoadBalancerFeignRequestTransformer.DEFAULT_ORDER)
public interface LoadBalancerFeignRequestTransformer {
int DEFAULT_ORDER = 0;
/**
* 将给定的请求对象以及选择的服务实例对象进过加工,转换为新的请求对象
*
* @param request 原始请求对象
* @param instance 服务实例
* @return 新的请求对象
*/
Request transformRequest(Request request, ServiceInstance instance);
public class XForwardedHeadersTransformer implements LoadBalancerFeignRequestTransformer {
private final ReactiveLoadBalancer.Factory<ServiceInstance> factory;
public XForwardedHeadersTransformer(ReactiveLoadBalancer.Factory<ServiceInstance> factory) {
this.factory = factory;
}
// 加工请求
@Override
public Request transformRequest(Request request, ServiceInstance instance) {
if (instance == null) {
return request;
}
LoadBalancerProperties.XForwarded xForwarded = factory.getProperties(instance.getServiceId()).getXForwarded();
if (xForwarded.isEnabled()) {
Map<String, Collection<String>> headers = new HashMap<>(request.headers());
URI uri = URI.create(request.url());
String xForwardedHost = uri.getHost();
String xForwardedProto = uri.getScheme();
headers.put("X-Forwarded-Host", Collections.singleton(xForwardedHost));
headers.put("X-Forwarded-Proto", Collections.singleton(xForwardedProto));
request = Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(), request.requestTemplate());
}
return request;
}
}
}
// 基于反射的Feign对象,Feign对象是整个Feign的核心类
public class ReflectiveFeign<C> extends Feign {
// 目标方法执行器的处理类解析器
private final ParseHandlersByName<C> targetToHandlersByName;
// 创建动态代理对象InvocationHandler的工厂类
private final InvocationHandlerFactory factory;
// 创建异步上下文的提供者,默认情况不提供异步上下文,只有在异步执行的时候才会有
private final AsyncContextSupplier<C> defaultContextSupplier;
public ReflectiveFeign(Contract contract, MethodHandler.Factory<C> methodHandlerFactory, InvocationHandlerFactory invocationHandlerFactory, AsyncContextSupplier<C> defaultContextSupplier) {
this.targetToHandlersByName = new ParseHandlersByName<C>(contract, methodHandlerFactory);
this.factory = invocationHandlerFactory;
this.defaultContextSupplier = defaultContextSupplier;
}
// 创建代理对象
public <T> T newInstance(Target<T> target) {
// 创建新的上下文对象,并返回代理对象
return newInstance(target, defaultContextSupplier.newContext());
}
// 创建FeignClient的代理对象
public <T> T newInstance(Target<T> target, C requestContext) {
// 验证目标对象中的方法是否符合规范,比如返回值,类必须是接口
TargetSpecificationVerifier.verify(target);
// 将目标接口FeignClient的所有方法转换为可执行的方法处理器
Map<Method, MethodHandler> methodToHandler = targetToHandlersByName.apply(target, requestContext);
// 创建InvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 创建代理对象
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
// 使用代理对象绑定接口的默认方法
for (MethodHandler methodHandler : methodToHandler.values()) {
if (methodHandler instanceof DefaultMethodHandler) {
((DefaultMethodHandler) methodHandler).bindTo(proxy);
}
}
return proxy;
}
// Feign的代理对象执行器
public class FeignInvocationHandler implements InvocationHandler {
// 目标接口
private final Target target;
// 目标接口的所有方法->方法执行器的映射关系
private final Map<Method, MethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取到该方法对应的执行器进行执行
return dispatch.get(method).invoke(args);
}
}
// 目标方法执行器的处理类解析器
private static final class ParseHandlersByName<C> {
// 用于解析类中的所有方法的元数据信息,包括类注解,方法注解,参数注解
private final Contract contract;
// 创建方法处理器的工厂
private final MethodHandler.Factory<C> factory;
public ParseHandlersByName(Contract contract, MethodHandler.Factory<C> factory) {
this.contract = contract;
this.factory = factory;
}
// 将目标接口FeignClient的所有方法转换为可执行的方法处理器
public Map<Method, MethodHandler> apply(Target target, C requestContext) {
final Map<Method, MethodHandler> result = new LinkedHashMap<>();
// 解析目标类的方法元数据信息
final List<MethodMetadata> metadataList = contract.parseAndValidateMetadata(target.type());
// 遍历所有的方法元数据
for (MethodMetadata md : metadataList) {
// 排除Object的方法
final Method method = md.method();
if (method.getDeclaringClass() == Object.class) {
continue;
}
// 创建方法处理器
final MethodHandler handler = this.createMethodHandler(target, md, requestContext);
// 保存方法->方法执行器的映射关系
result.put(method, handler);
}
// 处理接口的默认方法
for (Method method : target.type().getMethods()) {
if (Util.isDefault(method)) {
// 默认方法是有DefaultMethodHandler执行
final MethodHandler handler = new DefaultMethodHandler(method);
// 保存方法->方法执行器的映射关系
result.put(method, handler);
}
}
return result;
}
// 创建方法执行器
private MethodHandler createMethodHandler(Target<?> target, MethodMetadata md, C requestContext) {
// 如果方法设置了被忽略,那么执行该方法将会抛出一个异常
if (md.isIgnored()) {
return args -> {
throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
};
}
// 创建方法执行器
return factory.create(target, md, requestContext);
}
}
// 目标接口验证器
private static class TargetSpecificationVerifier {
// 验证
public static <T> void verify(Target<T> target) {
Class<T> type = target.type();
// 必须是接口
if (!type.isInterface()) {
throw new IllegalArgumentException("Type must be an interface: " + type);
}
// 遍历所有的方法
for (final Method m : type.getMethods()) {
final Class<?> retType = m.getReturnType();
// 验证返回值为CompletableFuture的情况,如果不是,则不验证
if (!CompletableFuture.class.isAssignableFrom(retType)) {
continue;
}
// 只能使用CompletableFuture,CompletableFuture的子类都不行
if (retType != CompletableFuture.class) {
throw new IllegalArgumentException("Method return type is not CompleteableFuture: " + getFullMethodName(type, retType, m));
}
// 获取方法CompletableFuture泛型
final Type genRetType = m.getGenericReturnType();
// 如果不存在泛型,抛出异常
// 也就是必须有泛型
if (!(genRetType instanceof ParameterizedType)) {
throw new IllegalArgumentException("Method return type is not parameterized: " + getFullMethodName(type, genRetType, m));
}
// 并且泛型是具体的类,不能是通配符
if (((ParameterizedType) genRetType).getActualTypeArguments()[0] instanceof WildcardType) {
throw new IllegalArgumentException("Wildcards are not supported for return-type parameters: " + getFullMethodName(type, genRetType, m));
}
}
}
// 获取方法名全称
private static String getFullMethodName(Class<?> type, Type retType, Method m) {
return retType.getTypeName() + " " + type.toGenericString() + "." + m.getName();
}
}
}
// 方法处理器,具体执行方法的类
public interface MethodHandler {
// 执行目标方法
Object invoke(Object[] argv) throws Throwable;
// 创建方法处理器MethodHandler的工厂类
public interface Factory<C> {
MethodHandler create(Target<?> target, MethodMetadata md, C requestContext);
}
// 同步执行的方法执行器
public class SynchronousMethodHandler implements MethodHandler {
// 方法元数据
private final MethodMetadata metadata;
// 目标类信息
private final Target<?> target;
// 发送Http请求的客户端
private final Client client;
// 重试器
private final Retryer retryer;
// 请求拦截器
private final List<RequestInterceptor> requestInterceptors;
// 日志对象
private final Logger logger;
// 日志级别对象
private final Logger.Level logLevel;
// 请求模板工厂
private final RequestTemplate.Factory buildTemplateFromArgs;
// 请求参数配置
private final Options options;
// 异常的传播机制
private final ExceptionPropagationPolicy propagationPolicy;
// 响应处理器
private final ResponseHandler responseHandler;
// 执行目标方法
@Override
public Object invoke(Object[] argv) throws Throwable {
// 使用工厂创建请求模板对象
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 重找请求配置信息
Options options = this.findOptions(argv);
// 克隆请求重试的信息
Retryer retryer = this.retryer.clone();
// 不断重试
while (true) {
try {
// 执行请求
return this.executeAndDecode(template, options);
}
// 只有抛出RetryableException才会重试,其他异常不会重试,而是抛出
catch (RetryableException e) {
try {
// 重试
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
// 如果传播策略为无需包装,则返账原有异常
if (propagationPolicy == UNWRAP && cause != null) {
throw cause;
}
// 否则返回包装的RetryableException
else {
throw th;
}
}
// 打印日志
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
// 执行并对响应体解码
public Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
// 执行所有的请求拦截器并返回请求对象
Request request = this.targetRequest(template);
// 打印请求日志
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
// 响应对象
Response response;
// 请求开始时间
long start = System.nanoTime();
try {
// 发送http请求
response = client.execute(request, options);
// 封装为响应对象,设置一些参数
response = response.toBuilder().request(request).requestTemplate(template).build();
} catch (IOException e) {
// 打印异常日志
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
}
throw errorExecuting(request, e);
}
// 记录执行结束时间
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
// 使用响应处理器处理响应
return responseHandler.handleResponse(metadata.configKey(), response, metadata.returnType(), elapsedTime);
}
// 执行所有的请求拦截器
public Request targetRequest(RequestTemplate template) {
// 执行拦截器
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
// 给请求模板设置目标url,并返回请求目标的request对象
return target.apply(template);
}
// 查找发送请求的配置对象
public Options findOptions(Object[] argv) {
// 如果不存在任何参数,返回当前对象的配置信息
if (argv == null || argv.length == 0) {
return this.options;
}
// 如果存在给定参数,从参数中找到Options类型的参数作为配置对象,如果参数中也不存在,则返回当前对象的配置信息
return Stream.of(argv).filter(Options.class::isInstance).map(Options.class::cast).findFirst().orElse(this.options);
}
// 生成MethodHandler的工厂
public static class Factory implements MethodHandler.Factory<Object> {
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final ResponseHandler responseHandler;
private final Logger logger;
private final Logger.Level logLevel;
private final ExceptionPropagationPolicy propagationPolicy;
// 请求模板RequestTemplate的工厂解析器,用于解析请求模板对象的核心类
// 通过该解析器可以解析到RequestTemplateFactory,然通过RequestTemplateFactory创建RequestTemplate对象
private final RequestTemplateFactoryResolver requestTemplateFactoryResolver;
private final Options options;
// 创建对象
public MethodHandler create(Target<?> target, MethodMetadata md, Object requestContext) {
// 使用请求模板工厂解析目标类对应的方法元数据,得到请求模板工厂类
// 该工厂会根据执行参数解析成请求模板RequestTemplate对象
final RequestTemplate.Factory buildTemplateFromArgs = requestTemplateFactoryResolver.resolve(target, md);
// 创建同步的方法执行器
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger, logLevel, md, buildTemplateFromArgs, options, responseHandler, propagationPolicy);
}
}
}
}
// 创建动态代理对象InvocationHandler的工厂类
public interface InvocationHandlerFactory {
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);
// 默认的实现
static final class Default implements InvocationHandlerFactory {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
}
// 请求模板RequestTemplate的工厂解析器,用于解析请求模板对象的核心类
// 通过该解析器可以解析到RequestTemplateFactory,然通过RequestTemplateFactory创建RequestTemplate对象
public class RequestTemplateFactoryResolver {
// 请求体编码器
private final Encoder encoder;
// 将请求参数转换为map的编码请
private final QueryMapEncoder queryMapEncoder;
public RequestTemplateFactoryResolver(Encoder encoder, QueryMapEncoder queryMapEncoder) {
this.encoder = checkNotNull(encoder, "encoder");
this.queryMapEncoder = checkNotNull(queryMapEncoder, "queryMapEncoder");
}
// 解析目标方法元数据,根据给请求模板设置的Body来指定不同的模板工厂
public RequestTemplate.Factory resolve(Target<?> target, MethodMetadata md) {
// 如果存在表单参数,并且没有请求body参数
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
return new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
}
// 如果存在body参数,或者该方法设置了总是编码body
if (md.bodyIndex() != null || md.alwaysEncodeBody()) {
return new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
}
return new BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
}
// 通过解析参数构建模板对象
private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory {
// 将方法参数转换为map的编码器
private final QueryMapEncoder queryMapEncoder;
// 方法元数据对象
protected final MethodMetadata metadata;
// 目标接口
protected final Target<?> target;
// 方法参数下标对应的转换为String参数类型的扩展器
private final Map<Integer, Param.Expander> indexToExpander = new LinkedHashMap<Integer, Param.Expander>();
private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder, Target target) {
this.metadata = metadata;
this.target = target;
this.queryMapEncoder = queryMapEncoder;
if (metadata.indexToExpander() != null) {
indexToExpander.putAll(metadata.indexToExpander());
return;
}
if (metadata.indexToExpanderClass().isEmpty()) {
return;
}
// 实例化Param.Expander的class类
for (Map.Entry<Integer, Class<? extends Param.Expander>> indexToExpanderClass : metadata.indexToExpanderClass().entrySet()) {
indexToExpander.put(indexToExpanderClass.getKey(), indexToExpanderClass.getValue().newInstance());
}
}
@Override
public RequestTemplate create(Object[] argv) {
// 创建请求模板对象
RequestTemplate mutable = RequestTemplate.from(metadata.template());
// 设置目标对象
mutable.feignTarget(target);
// 设置
if (metadata.urlIndex() != null) {
// 获取参数为URI的类型的下标
int urlIndex = metadata.urlIndex();
// 校验参数
checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
// 设置访问的目标URL
mutable.target(String.valueOf(argv[urlIndex]));
}
// 所有的请求参数变量
Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();
// 遍历所有的参数下标->参数名称的集合
for (Map.Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {
// 参数下标
int i = entry.getKey();
// 参数值
Object value = argv[i];
// 如果值为空,则跳过
if (value != null) {
if (indexToExpander.containsKey(i)) {
// 方法参数下标对应的转换为String参数类型的扩展器
// 如果value为集合,则返回List<String>,否则返回String
value = expandElements(indexToExpander.get(i), value);
}
// 遍历所有的参数名称
for (String name : entry.getValue()) {
// 保存参数名->参数值的映射
varBuilder.put(name, value);
}
}
}
// 解析这些请求相关配置
RequestTemplate template = this.resolve(argv, mutable, varBuilder);
// 参数为Map的并且为query参数的索引下标(例如,标注了参数注解@QueryMap)
if (metadata.queryMapIndex() != null) {
// 获取参数值
Object value = argv[metadata.queryMapIndex()];
// 将参数值转换为Map,如果是map则不需要转换,如果不是map,则需要使用queryMapEncoder进行转换
Map<String, Object> queryMap = toQueryMap(value);
// 添加请求参数到模板对象中
template = addQueryMapQueryParameters(queryMap, template);
}
// 参数为Map的并且为header的索引下标(例如,标注了参数注解@HeaderMap)
if (metadata.headerMapIndex() != null) {
// 获取参数值
Object value = argv[metadata.headerMapIndex()];
// 将参数值转换为Map,如果是map则不需要转换,如果不是map,则需要使用queryMapEncoder进行转换
Map<String, Object> headerMap = toQueryMap(value);
// 添加请求头到模板对象中
template = addHeaderMapHeaders(headerMap, template);
}
return template;
}
// 将参数值转换为Map,如果是map则不需要转换,如果不是map,则需要使用queryMapEncoder进行转换
private Map<String, Object> toQueryMap(Object value) {
if (value instanceof Map) {
return (Map<String, Object>) value;
}
return queryMapEncoder.encode(value);
}
// 执行参数的扩展方法,将参数转换为String类型,最终发送请求参数
private Object expandElements(Param.Expander expander, Object value) {
// 将每一个参数进行转换
if (value instanceof Iterable) {
List<String> values = new ArrayList<String>();
for (Object element : value) {
if (element != null) {
values.add(expander.expand(element));
}
}
return values;
}
// 直接转换
return expander.expand(value);
}
// 解析请求模板
protected RequestTemplate resolve(Object[] argv, RequestTemplate mutable, Map<String, Object> variables) {
return mutable.resolve(variables);
}
}
// 通过参数构建表单编码器模板对象
private static class BuildFormEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs {
// 编码器
private final Encoder encoder;
private BuildFormEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, QueryMapEncoder queryMapEncoder, Target target) {
super(metadata, queryMapEncoder, target);
this.encoder = encoder;
}
@Override
protected RequestTemplate resolve(Object[] argv, RequestTemplate mutable, Map<String, Object> variables) {
Map<String, Object> formVariables = new LinkedHashMap<String, Object>();
// 保存表单参数
for (Map.Entry<String, Object> entry : variables.entrySet()) {
if (metadata.formParams().contains(entry.getKey())) {
formVariables.put(entry.getKey(), entry.getValue());
}
}
// 使用编码器对表单参数进行编码,并且值到body中,因为表单可能含有文件
encoder.encode(formVariables, Encoder.MAP_STRING_WILDCARD, mutable);
// 解析请求模板对象
return super.resolve(argv, mutable, variables);
}
}
// 通过参数构建普通编码器模板对象
private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs {
// 编码器
private final Encoder encoder;
private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder, QueryMapEncoder queryMapEncoder, Target target) {
super(metadata, queryMapEncoder, target);
this.encoder = encoder;
}
@Override
protected RequestTemplate resolve(Object[] argv, RequestTemplate mutable, Map<String, Object> variables) {
// 是否标注了总是需要编码body
boolean alwaysEncodeBody = mutable.methodMetadata().alwaysEncodeBody();
Object body = null;
// 如果未设置
if (!alwaysEncodeBody) {
// 校验body参数
body = argv[metadata.bodyIndex()];
checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex());
}
// 如果设置了
if (alwaysEncodeBody) {
// 将参数进行编码,并设置到body中
body = argv == null ? new Object[0] : argv;
encoder.encode(body, Object[].class, mutable);
} else {
encoder.encode(body, metadata.bodyType(), mutable);
}
// 解析请求模板对象
return super.resolve(argv, mutable, variables);
}
}
}
// 响应结果处理器
public class ResponseHandler {
// 最大响应缓冲区大小
private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
// 日志级别
private final Level logLevel;
// 日志对象
private final Logger logger;
// 解码器,将响应体解码成返回值
private final Decoder decoder;
// 错误解码器,就是处理错误的响应结果的处理器(例如处理404,400)
// 也就是如何返回指定的异常通知下一步需要做什么,例如: 抛出RetryableException表示继续发起重试
private final ErrorDecoder errorDecoder;
// 是否应该解码404而不是抛出feigexception,默认为false
// 如果为true,404也会返回对应的结果
private final boolean dismiss404;
// 解码之后是否关闭资源(默认为true)
private final boolean closeAfterDecode;
// 响应拦截器,负责解码操作
// 每一个FeignClient只需要存在一个响应拦截器,如果需要多个拦截器配合工作,我们可以自定义ResponseInterceptor,管理所有的ResponseInterceptor进行工作
private final ResponseInterceptor responseInterceptor;
// 处理响应结果
public Object handleResponse(String configKey, Response response, Type returnType, long elapsedTime) throws Exception {
try {
// 打印响应的相关日志
response = logAndRebufferResponseIfNeeded(configKey, response, elapsedTime);
// 如果方法返回值就是Response
if (returnType == Response.class) {
// 如果响应体的内容大小大于最大的缓冲区,则断开响应体,关闭流(响应体可能就是流)
return disconnectResponseBodyIfNeeded(response);
}
// 是否需要解码响应体,根据请求状态决定
final boolean shouldDecodeResponseBody = (response.status() >= 200 && response.status() < 300) || (response.status() == 404 && dismiss404 && !isVoidType(returnType));
// 如果不需要,抛出异常
if (!shouldDecodeResponseBody) {
// 使用错误编码器进行编码
throw errorDecoder.decode(methodKey, response);
}
// 正确结果,对结果进行解码
return this.decode(response, returnType);
} catch (final IOException e) {
// 根据日志级别打印日志信息
if (logLevel != Level.NONE) {
logger.logIOException(configKey, logLevel, e, elapsedTime);
}
throw errorReading(response.request(), response, e);
}
}
// 打印响应的相关日志
private Response logAndRebufferResponseIfNeeded(String configKey, Response response, long elapsedTime) throws IOException {
if (logLevel == Level.NONE) {
return response;
}
return logger.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
}
// 如果需要,断开响应体(响应体可能就是流)
private static Response disconnectResponseBodyIfNeeded(Response response) throws IOException {
// 是否需要断开响应体,存在body,并且body已经超过最大的缓冲大小了
final boolean shouldDisconnectResponseBody =
response.body() != null
&& response.body().length() != null
&& response.body().length() <= MAX_RESPONSE_BUFFER_SIZE;
// 如果不需要,直接返回
if (!shouldDisconnectResponseBody) {
return response;
}
// 需要断开响应体
try {
// 返回新的Response对象
final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
} finally {
// 关闭响应体(响应体可能就是流)
response.body().close();
}
}
// 解码响应体
private Object decode(Response response, Type type) throws IOException {
// 如果是void,返回null
if (isVoidType(type)) {
// 关闭响应体
response.body().close();
return null;
}
try {
// 执行所有响应拦截器,得到最终的的结果
final Object result = responseInterceptor.aroundDecode(new InvocationContext(decoder, type, response));
// 如果解码后需要关闭资源
if (closeAfterDecode) {
// 关闭响应体
response.body().close();
}
// 返回编码后的结果
return result;
} catch (Exception e) {
response.body().close();
throw e;
}
}
}
SpringCloudOpenFeign的核心组件总结
最新推荐文章于 2024-06-20 17:00:23 发布