執行個體調用過程
feign的核心主要分兩塊:
1,初始化
feign通過Feign.builder() 構造器建構傳遞初始化參數,如:發起http的工具,序列化工具,目标類,生産者位址等參數
然後解析目标類注解為每個方法生成對應的MethodHandler ,
然後使用jdk動态代理為目标類生成代理執行個體ReflectiveFeign.FeignInvocationHandler
2,調用過程
調用目标類執行個體方法實際調用的是代理對象 ReflectiveFeign.FeignInvocationHandler.invoke–>
同步調用方法處理器 SynchronousMethodHandler.invoke–> ApacheHttp裝飾者 ApacheHttpClient.execute
測試接口
public interface TestFeignClient {
@GET
@Path("test")
String test(String str);
}
1,初始化過程,脫離spring自動裝配的情況下,使用TestFeignClient,建立目标類接口的代理類執行個體
TestFeignClient target = Feign.builder()
.client(new ApacheHttpClient())
.contract(new JAXRS2Contract())
.decoder(new JacksonDecoder())
.encoder(new JacksonEncoder())
.target(TestFeignClient.class, "http://" + testClient);
Feign.builder() 基礎建構器
.client(new ApacheHttpClient()) 選擇具體發起http請求的工具
由ApacheHttpClient 類實作 實作feign.Client 接口,
核心實作方法execute(),通過解析轉換feign.Request 為 org.apache.http.HttpResponse
然後通過apache.HttpClient 發起請求
.contract(new JAXRS2Contract()) 使用 JAX-RS 2 注解辨別請求
.decoder(new JacksonDecoder()) 解碼器
.encoder(new JacksonEncoder()) 編碼器
.target(TestFeignClient.class, "http://" + testClient); 使用jdk動态代理生成代理對象
基礎建構之後建立預設對象 ReflectiveFeign
1,new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
2,調用 ReflectiveFeign.newInstance(target); 建立執行個體
@Override
public <T> T newInstance(Target<T> target) {
//解析接口中方法請求注解 和參數相關中繼資料
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
//生成代理處理器,調用的還是ReflectiveFeign 由他來的内部類FeignInvocationHandler實作jdk
// 動态代理類 InvocationHandler接口
// @Override
// public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
// return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
// }
//
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
2,接口調用過程
我們使用上一步擷取到的TestFeignClient執行個體直接調用 接口的方法TestFeignClient.test("aaa")
當我們調用此執行個體的方法實際調用的是代理 ReflectiveFeign.FeignInvocationHandler.invoke 方法
ReflectiveFeign.FeignInvocationHandler.invoke
//目标類
private final Target target;
//解析目标類緩存方法對應請求
private final Map<Method, MethodHandler> 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();
}
//實際調用
return dispatch.get(method).invoke(args);
}
SynchronousMethodHandler 繼承 MethodHandler 實作同步調用請求
@Override
public Object invoke(Object[] argv) throws Throwable {
//通過請求參數生成請求模闆
RequestTemplate template = buildTemplateFromArgs.create(argv);
//請求相關參數,timeout等
Options options = findOptions(argv);
//重試機制
Retryer retryer = this.retryer.clone();
while (true) {
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 {
throw th;
}
}
if (logLevel != Logger.Level.NONE) {
logger.logRetry(metadata.configKey(), logLevel);
}
continue;
}
}
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
//生成feign 請求對象
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//調用 ApacheHttpClient feign 的裝飾者請求類
response = client.execute(request, options);
// ensure the request is set. TODO: remove in Feign 12
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);
if (decoder != null)
return decoder.decode(response, metadata.returnType());
CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
metadata.returnType(),
elapsedTime);
try {
if (!resultFuture.isDone())
throw new IllegalStateException("Response handling not done");
return resultFuture.join();
} catch (CompletionException e) {
Throwable cause = e.getCause();
if (cause != null)
throw cause;
throw e;
}
}
ApacheHttpClient.execute 最終調用
private final HttpClient client;
@Override
public Response execute(Request request, Request.Options options) throws IOException {
HttpUriRequest httpUriRequest;
try {
//feign request 轉換為ApacheHttpClient httpUriRequest
httpUriRequest = toHttpUriRequest(request, options);
} catch (URISyntaxException e) {
throw new IOException("URL '" + request.url() + "' couldn't be parsed into a URI", e);
}
//由 ApacheHttpClient 發起最終請求
HttpResponse httpResponse = client.execute(httpUriRequest);
return toFeignResponse(httpResponse, request);
}