共计 10511 个字符,预计需要花费 27 分钟才能阅读完成。
本系列代码地址:https://github.com/JoJoTec/sp…
接下来,咱们开始剖析 OpenFeign 的生命周期,联合 OpenFeign 自身的源代码。首先是从接口定义创立 OpenFeign 代理开始。咱们这里只关怀同步客户端,因为异步客户端目前还在实现中,并且在咱们的我的项目中,异步响应式的客户端不必 OpenFeign,而是用的官网的 WebClient
创立 OpenFeign 代理
创立 OpenFeign 代理,次要分为以下几步:
- 应用 Contract 解析接口的每一个办法,生成每一个办法的元数据列表:
List<MethodMetadata> metadata
- 依据每一个
MethodMetadata
,生成对应的申请模板工厂RequestTemplate.Factory
,用于生成前面的申请。同时,应用这个模板工厂以及其余配置生成对应的办法处理器MethodHandler
,对于同步的 OpenFeign,MethodHandler
实现为SynchronousMethodHandler
。将接口办法与MethodHandler
一一对应建设映射,后果为Map<Method, MethodHandler> methodToHandler
。对于 Java 8 引入的 interface default 办法,须要用不同MethodHandler
,即DefaultMethodHandler
,因为这种办法不必代理,不必生成对应的 http 调用,其实现为间接调用对应的 default 办法代码。 - 应用 InvocationHandlerFactory 这个工厂,创立
InvocationHandler
用于代理调用。 - 调用 JDK 动静代理生成类办法应用
InvocationHandler
创立代理类。
创立 OpenFeign 代理,次要基于 JDK 的动静代理实现。咱们先举一个简略的例子,创立一个 JDK 动静代理,用来类比。
JDK 动静代理
应用 JDK 动静代理,须要如下几个步骤:
1. 编写接口以及对应的代理类 。咱们这里编写一个简略的接口和对应的实现类:
public interface TestService {void test();
}
public class TestServiceImpl implements TestService {
@Override
public void test() {System.out.println("TestServiceImpl#test is called");
}
}
2. 创立代理类实现 java.lang.reflect.InvocationHandler
,并且,在外围办法中,调用理论的对象,这里即咱们下面 TestService 的实现类 TestServiceImpl 的对象。
JDK 中有内置的动静代理 API,其外围是 java.lang.reflect.InvocationHandler
。咱们先来创立一个简略的 InvocationHandler
实现类:
public class SimplePrintMethodInvocationHandler implements InvocationHandler {
private final TestService testService;
public SimplePrintMethodInvocationHandler(TestService testService) {this.testService = testService;}
@Override
public Object invoke(
// 代理对象
Object proxy,
// 调用的办法
Method method,
// 应用的参数
Object[] args)
throws Throwable {System.out.println("Invoked method:" + method.getName());
// 进行理论的调用
return method.invoke(testService, args);
}
}
3. 创立代理对象,并应用代理对象调用 。个别通过 Proxy 的静态方法去创立,例如:
// 首先,创立要代理的对象
TestServiceImpl testServiceImpl = new TestServiceImpl();
// 而后应用要代理的对象创立对应的 InvocationHandler
SimplePrintMethodInvocationHandler simplePrintMethodInvocationHandler = new SimplePrintMethodInvocationHandler(testServiceImpl);
// 创立代理类,因为一个类可能实现多个接口,所以这里返回的是 Object,用户依据本人须要强制转换成要用的接口
Object proxyInstance = Proxy.newProxyInstance(TestService.class.getClassLoader(),
testServiceImpl.getClass().getInterfaces(),
simplePrintMethodInvocationHandler
);
// 强制转换
TestService proxied = (TestService) proxyInstance;
// 应用代理对象进行调用
proxied.test();
这样,咱们就应用了 JDK 的内置动静代理机制实现了一个简略的动静代理。在 OpenFeign 的应用中,和咱们的示例有一点区别。首先,咱们只须要定义要代理的接口,不必定义实现类。因为所有的 OpenFeign 接口要做的事件其实都是 HTTP 调用,其信息能够主动从接口定义中生成,咱们能够应用对立的对象依据接口定义,承载 OpenFeign 接口定义的申请。在 OpenFeign 中,这个等同于实现对象的,就是依据接口生成的 MethodHandler,在同步的 OpenFeign 中,即 feign.SynchronousMethodHandler
。之后,OpenFeign 创立的 InvocationHandler,其实就是将调用转发到对应的 SynchronousMethodHandler
的对应办法。
创立 OpenFeign 代理对象的流程详解
咱们应用后面的例子,来看一下创立代理的流程:
interface GitHub {
/**
* 定义 get 办法,包含门路参数,响应返回序列化类
* @param owner
* @param repository
* @return
*/
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repository);
/**
* 响应体构造类
*/
class Contributor {
String login;
int contributions;
public Contributor() {}
public String getLogin() {return login;}
public void setLogin(String login) {this.login = login;}
public int getContributions() {return contributions;}
public void setContributions(int contributions) {this.contributions = contributions;}
}
}
/**
* 基于 FastJson 的反序列化解码器
*/
static class FastJsonDecoder implements Decoder {
@Override
public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
// 读取 body
byte[] body = response.body().asInputStream().readAllBytes();
return JSON.parseObject(body, type);
}
}
public static void main(String[] args) {
// 创立 Feign 代理的 HTTP 调用接口实现
GitHub github = Feign.builder()
// 指定解码器为 FastJsonDecoder
.decoder(new FastJsonDecoder())
// 指定代理类为 GitHub,基址为 https://api.github.com
.target(GitHub.class, "https://api.github.com");
List<GitHub.Contributor> contributors = github.contributors("OpenFeign", "feign");
}
咱们这里关怀的其实就是创立 Feign 代理的 HTTP 调用接口实现这一步的外部流程。首先咱们来看 Feign 的 Builder 的构造,当咱们初始化一个 Feign 的 Builder 也就是调用 Feign.builder()
时,会创立如下组件(同时也阐明以下组件都是能够配置的,如果一些配置之前没有提到,则能够):
// 申请拦截器列表,默认为空
private final List<RequestInterceptor> requestInterceptors = new ArrayList();
// 日志级别,默认不打印任何日志
private Level logLevel = Level.NONE;
// 负责解析类元数据的 Contract,默认是反对 OpenFeign 内置注解的默认 Contract
private Contract contract = new Contract.Default();
// 承载 HTTP 申请的 Client,默认是基于 Java HttpURLConnection 的 Default Client
private Client client = new feign.Client.Default((SSLSocketFactory)null, (HostnameVerifier)null);
// 重试器,默认也是 Default
private Retryer retryer = new feign.Retryer.Default();
// 默认的日志 Logger,默认不记录任何日志
private Logger logger = new NoOpLogger();
// 编码器解码器也是默认的
private Encoder encoder = new feign.codec.Encoder.Default();
private Decoder decoder = new feign.codec.Decoder.Default();
// 查问参数编码,这个咱们个别不会批改
private QueryMapEncoder queryMapEncoder = new FieldQueryMapEncoder();
// 谬误编码器,默认为 Default
private ErrorDecoder errorDecoder = new feign.codec.ErrorDecoder.Default();
// 各种超时的 Options 走的默认配置
private Options options = new Options();
// 用来生成 InvocationHandler 的 Factory 也是默认的
private InvocationHandlerFactory invocationHandlerFactory = new feign.InvocationHandlerFactory.Default();
// 是否非凡解析 404 谬误,因为针对 404 咱们可能不想抛出异样,默认是 false
private boolean decode404 = false;
// 是否在解码后立即敞开 Response,默认为是
private boolean closeAfterDecode = true;
// 异样流传规定,默认是不流传
private ExceptionPropagationPolicy propagationPolicy = ExceptionPropagationPolicy.NONE;
// 是否强制解码,这个次要为了兼容异步 Feign 引入的配置,咱们间接疏忽,认为他就是 false 即可
private boolean forceDecoding = false;
private List<Capability> capabilities = new ArrayList();
咱们的代码中指定了指定解码器为 FastJsonDecoder,所以 Decoder 就是 FastJsonDecoder 了。最初通过 target(GitHub.class, "https://api.github.com");
指定定代理类为 GitHub,基址为 https://api.github.com,这时候就会生成 Feign 代理类,其步骤是:
Feign
public <T> T target(Class<T> apiType, String url) {
// 应用代理接口类型,以及基址创立 HardCodedTarget,他的意思其实就是硬编码的 Target
return target(new HardCodedTarget<T>(apiType, url));
}
public <T> T target(Target<T> target) {return build().newInstance(target);
}
public Feign build() {
// 将所有组件通过所有的 Capability,从这里咱们能够看出,咱们能够实现 Capability 接口来在创立 Feign 代理的时候动静批改组件
Client client = Capability.enrich(this.client, capabilities);
Retryer retryer = Capability.enrich(this.retryer, capabilities);
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Encoder encoder = Capability.enrich(this.encoder, capabilities);
Decoder decoder = Capability.enrich(this.decoder, capabilities);
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
// 创立 SynchronousMethodHandler 的 Factory,用于生成 SynchronousMethodHandler,SynchronousMethodHandler 是理论承载 Feign 代理申请的实现类
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
// 通过办法名称来辨别不同接口办法的元数据解析,用于生成并路由到对应的代理办法
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
// 创立 ReflectiveFeign
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
创立 ReflectiveFeign 之后,会调用其中的 newInstance 办法:
ReflectiveFeign
public <T> T newInstance(Target<T> target) {
// 应用后面提到的 ParseHandlersByName 解析元数据并生成所有须要代理的办法的 MethodHandler,咱们这里剖析的是同步 Feign,所以是 SynchronousMethodHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
// 将办法与对应的 MethodHandler 一一对应
for (Method method : target.type().getMethods()) {if (method.getDeclaringClass() == Object.class) {
// 对于 Object 的办法,间接跳过
continue;
} else if (Util.isDefault(method)) {
// 如果是 java 8 中接口的默认办法,就应用 DefaultMethodHandler 解决
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
// 应用后面 Builder 中的 InvocationHandlerFactory 创立 InvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 应用 InvocationHandler 创立 Proxy
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
// 将代理与 DefaultMethodHandler 关联
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
对于应用后面提到的 ParseHandlersByName 解析元数据并生成所有须要代理的办法的 MethodHandler 这一步,次要就波及到了应用 Contract 解析出办法的元数据,而后将这些元数据用对应的编码器绑定用于之后调用的编码:
ReflectiveFeign
public Map<String, MethodHandler> apply(Target target) {
// 应用 Contract 解析出所有办法的元数据
List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
// 对于每个解析出的办法元数据
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
// 有表单的状况
buildTemplate =
new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
} else if (md.bodyIndex() != null) {
// 有 body 的状况
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
} else {
// 其余状况
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
}
if (md.isIgnored()) {result.put(md.configKey(), args -> {throw new IllegalStateException(md.configKey() + "is not a method handled by feign");
});
} else {
// 应用 SynchronousMethodHandler 的 Factory 生成 SynchronousMethodHandler
result.put(md.configKey(),
factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
}
}
return result;
}
}
默认的 InvocationHandlerFactory 生成的 InvocationHandler 是 ReflectiveFeign.FeignInvocationHandler:
static final class Default implements InvocationHandlerFactory {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
其中的内容是:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 对于 equals,hashCode,toString 办法间接调用
if ("equals".equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {return false;}
} else if ("hashCode".equals(method.getName())) {return hashCode();
} else if ("toString".equals(method.getName())) {return toString();
}
// 对于其余办法,调用对应的 SynchronousMethodHandler 进行解决
return dispatch.get(method).invoke(args);
}
从这里咱们就能够看出,咱们生成的 Proxy,其实就是将申请代理到了 SynchronousMethodHandler 上。
咱们这一节具体介绍了 OpenFeign 创立代理的具体流程,能够看出,对于同步 Feign 生成的 Proxy,其实就是将接口 HTTP 申请定义的办法申请代理到了 SynchronousMethodHandler 上。下一节咱们会详细分析 SynchronousMethodHandler 做理论 HTTP 调用的流程,来搞清楚 Feign 所有组件是如何协调工作的。
微信搜寻“我的编程喵”关注公众号,每日一刷,轻松晋升技术,斩获各种 offer: