spring-cloud 里面的组件太多了,前段时间又接触到一个名字叫做Feign的,然后在CSDN看了很多大神写的这类文章,按照自己思路整理一下,就是为了加深下印象,萤火之光也不敢与日月争辉,但也希望对大家有帮助
1、我们先抛开spring-cloud 来说Fegin,我们之前做一个HTTP接口调用我们可以用JDK自带的HttpURLConnection,也可以用OKHttp3、RestTemplate等类库,来看我们用Fegin来实现一个
UTF-8
10.3.0
io.github.openfeign
feign-core
${feign.version}
io.github.openfeign
feign-gson
${feign.version}
io.github.openfeign
feign-okhttp
${feign.version}
io.github.openfeign
feign-jackson
${feign.version}
我们先来定义一个接口叫CsdnHub.java
public interface CsdnHub {
@RequestLine("GET /Houson_c/article/details/84933840")
String get();
}
然后我们直接用Feign来调用它,代码如下:
/**
* main
*
* @param args
*/
public static void main(String[] args) {
//1、生成了一个CsdnHub接口代理类
CsdnHub csdnHub = Feign.builder().decoder(new Decoder.Default()).target(CsdnHub.class, "https://blog.csdn.net");
String csdnResult = csdnHub.get();
System.out.println(csdnResult);
}
代码很简单,csdnResult结果就是 https://blog.csdn.net/Houson_c/article/details/84933840 这个网址的HTML内容,在这里我们要思考一下,它是怎么做到的呢??
2、我们直接转到target(CsdnHub.class, "https://blog.csdn.net") 这个方法定义,我们先看build()方法定义
public T target(Class apiType, String url) {
return target(new HardCodedTarget(apiType, url));
}
//从这个方法入手,这个方法build()方法和newInstance()
public T target(Target target) {
return build().newInstance(target);
}
public Feign build() {
//1、创建一个methodhandler工厂类
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy);
//2、用于解析接口配置的注解
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
//3、创建RefectiveFeign对象
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
SynchronousMethodHandler.Factory代码贴出来,这个是SynchronousMethodHandler类中的内部类,代码如下
static class Factory {
private final Client client;
private final Retryer retryer;
private final List requestInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final boolean decode404;
private final boolean closeAfterDecode;
private final ExceptionPropagationPolicy propagationPolicy;
Factory(Client client, Retryer retryer, List requestInterceptors,
Logger logger, Logger.Level logLevel, boolean decode404, boolean closeAfterDecode,
ExceptionPropagationPolicy propagationPolicy) {
this.client = checkNotNull(client, "client");
this.retryer = checkNotNull(retryer, "retryer");
this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors");
this.logger = checkNotNull(logger, "logger");
this.logLevel = checkNotNull(logLevel, "logLevel");
this.decode404 = decode404;
this.closeAfterDecode = closeAfterDecode;
this.propagationPolicy = propagationPolicy;
}
public MethodHandler create(Target> target,
MethodMetadata md,
RequestTemplate.Factory buildTemplateFromArgs,
Options options,
Decoder decoder,
ErrorDecoder errorDecoder) {
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
logLevel, md, buildTemplateFromArgs, options, decoder,
errorDecoder, decode404, closeAfterDecode, propagationPolicy);
}
}
ParseHandlersByName 这个是解析接口注解的类,,这个是ReflectiveFeign类中的内部类,代码如下
static final class ParseHandlersByName {
private final Contract contract;
private final Options options;
private final Encoder encoder;
private final Decoder decoder;
private final ErrorDecoder errorDecoder;
private final QueryMapEncoder queryMapEncoder;
private final SynchronousMethodHandler.Factory factory;
ParseHandlersByName(
Contract contract,
Options options,
Encoder encoder,
Decoder decoder,
QueryMapEncoder queryMapEncoder,
ErrorDecoder errorDecoder,
SynchronousMethodHandler.Factory factory) {
this.contract = contract;
this.options = options;
this.factory = factory;
this.errorDecoder = errorDecoder;
this.queryMapEncoder = queryMapEncoder;
this.encoder = checkNotNull(encoder, "encoder");
this.decoder = checkNotNull(decoder, "decoder");
}
//apply
public Map apply(Target key) {
List metadata = contract.parseAndValidatateMetadata(key.type());
Map result = new LinkedHashMap();
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
}
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
}
3、接下来我们看newInstance()这个方法,看这个名字就大概能猜到这个方法会创建一个代理类,我们跟进去看看
public T newInstance(Target target) {
//1、这个方法就是解析定义的那些接口,然后打包Map 返回
Map nameToHandler = targetToHandlersByName.apply(target);
Map methodToHandler = new LinkedHashMap();
List defaultMethodHandlers = new LinkedList();
//2、遍历循环target定义的方法
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)));
}
}
//3、获取一个InvocationHandler实例,最后通过Proxy.newProxyInstance()代理对象
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;
}
总结:newInstance(Target
1-1:解释target接口中方法的注解信息,最后打包成Map
1-2:通过target 和 methodToHandler参数生成得到一个InvocationHandler对象实例(这个对象实例是FeignInvocationHandler
)
1-3:通过target 和 invocationhandler对象实例 调用Proxy.newProxyInstance() 生成动态代理对象
1-4:最后调用代理对象时可以去看InvocationHandler对象实例的invoke()方法,也就是FeignInvocationHandler 类中的invoke()这个方法
private final Map dispatch;
FeignInvocationHandler(Target target, Map 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 {
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();
}
//最后根据method 获取MethodHandler实例(也就是SynchronousMethodHandler对象中的invoke)
return dispatch.get(method).invoke(args);
}
接下来可以去看SynchronousMethodHandler类中invoke()方法,就可以看到
@Override
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = buildTemplateFromArgs.create(argv);
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 {
Request request = targetRequest(template);
if (logLevel != Logger.Level.NONE) {
logger.logRequest(metadata.configKey(), logLevel, request);
}
Response response;
long start = System.nanoTime();
try {
//1、这个里面就发起http请求了
response = client.execute(request, options);
} 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);
boolean shouldClose = true;
try {
if (logLevel != Logger.Level.NONE) {
response =
logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);
}
if (Response.class == metadata.returnType()) {
if (response.body() == null) {
return response;
}
if (response.body().length() == null ||
response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
// Ensure the response body is disconnected
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
} catch (IOException e) {
if (logLevel != Logger.Level.NONE) {
logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime);
}
throw errorReading(request, response, e);
} finally {
if (shouldClose) {
ensureClosed(response.body());
}
}
}
Feign上面流程清楚后,在看看大牛们画图这个流程图(我也是从别的大牛那边拷贝过来的),结合起来看效果更好
总结:Feign简化了各种Http请求操作,根据定义好的接口方法生成动态代理类HTTP目标方法