美文网首页
Feign源代码粗读

Feign源代码粗读

作者: 旅茗 | 来源:发表于2018-04-19 15:09 被阅读0次

Feign使用简单示例

定义好一个接口,用@RequestLine注解

public interface WxCorpDepartmentClient {
    @RequestLine("POST /cgi-bin/department/list?access_token={accessToken}")
    public DepartmentResult departments(@Param("accessToken") String accessToken);
}

实际发起请求的代码:

@Component
public class WxCorpPermanentCodeClientImpl extends BaseWxCorpClient<WxCorpPermanentCodeClient> implements WxCorpPermanentCodeClient {
    @Override
    public PermanentCodeResult corpPermanentCode(String suiteAccessToken, PermanentCodeRequest permanentCodeRequest) {
        return getFeignClient(WxCorpPermanentCodeClient.class).corpPermanentCode(suiteAccessToken, permanentCodeRequest);
    }
}

public class BaseWxCorpClient<T> {
    public T getFeignClient(Class<T> clazz) {
        return Feign.builder()
                .encoder(new GsonEncoder())
                .decoder(new GsonDecoder()).target(clazz, "https://qyapi.weixin.qq.com");
    }
}

源代码解析

核心类类图

image

由类图可知,Feign的实例的Class为 feign.ReflectiveFeign

ReflectiveFeign的创建过程

该实例采用Builder模式进行创建,在通常的使用中,我们写如下代码即可创建ReflectiveFeign的实例。

Feign.builder().encoder(new GsonEncoder()).decoder(new GsonDecoder()).target(clazz, "https://qyapi.weixin.qq.com")

Feign.builder()

通过Feign.builder()创建出Feign的构造器实例。在Builder的属性中,可以看到包括 Client、Retryer、Logger、Encoder、Decoder、Contract、Logger.Level等都是可以进行定义的。不过在builder中也对这些属性做了默认的配置。

    private Logger.Level logLevel = Logger.Level.NONE;
    private Contract contract = new Contract.Default();
    private Client client = new Client.Default(null, null);
    private Retryer retryer = new Retryer.Default();
    private Logger logger = new NoOpLogger();
    private Encoder encoder = new Encoder.Default();
    private Decoder decoder = new Decoder.Default();
    private ErrorDecoder errorDecoder = new ErrorDecoder.Default();

Builder.target(Class, String)

public <T> T target(Class<T> apiType, String url) {
      return target(new HardCodedTarget<T>(apiType, url));
}

public <T> T target(Target<T> target) {
  return build().newInstance(target);
}

public Feign build() {
  SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
      new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                                           logLevel, decode404);
  ParseHandlersByName handlersByName =
      new ParseHandlersByName(contract, options, encoder, decoder,
                              errorDecoder, synchronousMethodHandlerFactory);
  return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
}

通过Builder.build()方法,最后创建出ReflectiveFeign的实例。

image

ReflectiveFeign的两个属性,一个是ParseHandlersByName 另一个是InvocationHandlerFactory。

Feign.newInstance(Target)

在ReflectiveFeign中对newInstance方法的实现为:

  public <T> T newInstance(Target<T> target) {
    // 将Target包装的实际的对象的方法进行分析后,封装在map里.key就是方法的签名.
    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)));
      }
    }
    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;
  }

对应的nameToHanlder在内存中的调试结果为:

image

Feign对我们的接口做了代理,具体的实现是在 feign.ReflectiveFeign.FeignInvocationHandler 这个类中。

static 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 {
      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);
    }
  }

由代理对象的invoke可知,我们在实际调用接口方法的时候,会调用其invoke方法。

invoke方法中,根据方法获取到对应的MethodHandler,由调试的内存结果,我们看到是由SynchronousMethodHandler来进行处理的。下面是对应的invoke的处理逻辑。

  @Override
  public Object invoke(Object[] argv) throws Throwable {
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    Retryer retryer = this.retryer.clone();
    while (true) {
      try {
        return executeAndDecode(template);
      } catch (RetryableException e) {
        retryer.continueOrPropagate(e);
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }

相关文章

网友评论

      本文标题:Feign源代码粗读

      本文链接:https://www.haomeiwen.com/subject/oyuwkftx.html