Feign Reactive 源码随便看看

feign-reactive github

        Implementation of Feign on Spring WebClient. Brings you the best of two worlds together : concise syntax of Feign to write client side API on fast, asynchronous and non-blocking HTTP client of Spring WebClient.

        之前的 Feign 源码随便看看 是非响应式的,是不能用于 webflux 的应用,然而 Feign Reactive 是可以用于 webflux 应用的。底层使用了 webclient 非阻塞的 web 客户端。

还是从一个单元测试开始

        需要引入 feign reactive 的坐标 com.playtika.reactivefeign:feign-reactor-core:3.0.3 和 com.playtika.reactivefeign:feign-reactor-webclient:3.0.3

@SpringBootTest
class ReactiveFeignTest {

    public static String baseUrl;

    private static final String DEFAULT_BODY = "hello, world!";

    @BeforeAll
    public static void init() {
        // 初始化 mock web server,用于 mock http请求
        MockWebServer server = new MockWebServer();
        MockResponse mockResponse = new MockResponse().setBody(DEFAULT_BODY);
        server.enqueue(mockResponse);
        baseUrl = server.url("/default").toString();
    }

    // 测试客户端 feign 的请求模板定义
    interface TestClient {

        @RequestLine("GET /test/{owner}")
        Mono<String> test(@Param("owner") String owner);
    }

    @Test
    void testSimpleReactiveFeign() {
        // 使用 Feign 创建出 TestClient 的实例
        TestClient testClient = WebReactiveFeign.<TestClient>builder().target(TestClient.class, baseUrl);
        // 发起 http 调用
        String result = testClient.test("o").block();
        Assertions.assertEquals(DEFAULT_BODY, result);
    }
}

        还是之前的例子只不过改成了 WebReactiveFeign,模板接口的方法返回值改成 Mono 或者 Flux。

如何做到的非阻塞

        从 WebReactiveFeign#builder() 看起。

public class WebReactiveFeign {

    public static <T> Builder<T> builder() {
        return builder(WebClient.builder());
    }

    public static <T> Builder<T> builder(WebClient.Builder webClientBuilder) {
        return new Builder<>(webClientBuilder);
    }

    public static <T> Builder<T> builder(WebClient.Builder webClientBuilder,
                                         WebClientFeignCustomizer webClientCustomizer) {
        return new Builder<>(webClientBuilder, webClientCustomizer);
    }

    public static class Builder<T> extends CoreWebBuilder<T> {

    ......

    }
}

abstract public class CoreWebBuilder<T> extends ReactiveFeign.Builder<T>{

    protected CustomizableWebClientBuilder webClientBuilder;

    protected CoreWebBuilder(WebClient.Builder webClientBuilder) {
        this.webClientBuilder = new CustomizableWebClientBuilder(webClientBuilder);
        this.webClientBuilder.clientConnector(buildClientConnector());
        updateClientFactory();
    }

    // 主要是这个地方构建 ReactiveHttpClientFactory
    // 用于创建 ReactiveHttpClient 类似于 feign 中的 client 组件
    protected void updateClientFactory(){
        clientFactory(methodMetadata -> webClient(
                methodMetadata, webClientBuilder.build(), errorMapper()));
    }

    ......
}

        看到这里有个印象,feign reactive 不再通过实现 feign 中的 client 去实现响应式,因为 client 的返回值不是 Publisher<T> 类型的,所以用 ReactiveHttpClient 作为响应式的 client 抽象。

        看看 ReactiveHttpClient 的源码和 ReactiveHttpClientFactory 的源码。

public interface ReactiveHttpClientFactory {

    default void target(Target target){}

    ReactiveHttpClient create(MethodMetadata methodMetadata);

}

public interface ReactiveHttpClient<P extends Publisher<?>> {

	Mono<ReactiveHttpResponse<P>> executeRequest(ReactiveHttpRequest request);
}

       CoreWebBuilder#updateClientFactory 的大概意思是在调用 ReactiveHttpClientFactory#create() 会返回 ReactiveHttpClient 实例,这里具体返回的是 WebReactiveHttpClient。

public class WebReactiveHttpClient<P extends Publisher<?>> implements ReactiveHttpClient<P> {

    ......

    private final WebClient webClient;

    @Override
	public Mono<ReactiveHttpResponse<P>> executeRequest(ReactiveHttpRequest request) {
		return webClient.method(HttpMethod.valueOf(request.method()))
				.uri(request.uri())
				.headers(httpHeaders -> setUpHeaders(request, httpHeaders))
				.body(provideBody(request))
				.exchange()
				.onErrorMap(ex -> {
					Throwable errorMapped = errorMapper.apply(request, ex);
					if(errorMapped != null){
						return errorMapped;
					} else {
						return new ReactiveFeignException(ex, request);
					}
				})
				.map(response -> toReactiveHttpResponse(request, response));
	}

    ......
}

        真正是通过非阻塞的 webclient 实现的。

feign client 实例的构建过程

        继续回到 CoreWebBuilder,这个类继承了 ReactiveFeign.Builder ,最终调用了 ReactiveFeignBuilder#target() 创建出了 feign client 实例。

public interface ReactiveFeignBuilder<T> {

    ......

     /**
     * Defines target and builds client.
     *
     * @param apiType API interface
     * @param url base URL
     * @return built client
     */
    default T target(final Class<T> apiType, final String url) {
        return target(new Target.HardCodedTarget<>(apiType, url));
    }

    default T target(final Class<T> apiType, final String name, final String url) {
        if(name.equals(url)){
            throw new IllegalArgumentException(String.format("Name is equal to url: name=[%s], url=[%s]", name, url));
        }
        if(!url.contains(name)){
            throw new IllegalArgumentException(String.format("Name should be part of url: name=[%s], url=[%s]", name, url));
        }
        return target(new Target.HardCodedTarget<>(apiType, name, url));
    }

    /**
     * Defines target and builds client.
     *
     * @param target target instance
     * @return built client
     */
    default T target(final Target<T> target) {
        return build().newInstance(target);
    }

    default ReactiveFeign build() {
        return new ReactiveFeign(contract(),
                buildReactiveMethodHandlerFactory(buildReactiveClientFactory()),
                invocationHandlerFactory());
    }

/**
     * 解析方法中的注解,和 feign 中的一样
     */
    Contract contract();

    /**
     * 创建 构建ReactiveInvocationHandler的工厂
     * ReactiveInvocationHandler主要做的就是
     * dispatch.get(method).invoke(args);
     */
    default InvocationHandlerFactory invocationHandlerFactory(){
        return new ReactiveInvocationHandler.Factory();
    }

    /**
     * MethodHandlerFactory 是 feign reactive 新添加的组件
     * 用于创建 MethodHandler
     * PublisherClientFactory 用于创建 PublisherClient
     * PublisherClient 中持有 ReactiveHttpClient 对象
     * MethodHandler 中持有 PublisherClient 对象
     * 所以 ReactiveInvocationHandler -> dispatch.get(method).invoke(args)
     *     -> MethodHandler -> PublisherClient -> ReactiveHttpClient -> 发起请求
     */
    MethodHandlerFactory buildReactiveMethodHandlerFactory(PublisherClientFactory reactiveClientFactory);

    /**
     * 构建PublisherClientFactory实例
     */
    PublisherClientFactory buildReactiveClientFactory();
}

        最终调用的是 ReactiveFeign#newInstance() 创建实例。从这里开始就有点绕了,注意 ReactiveFeign 的构造函数,调用了下面的四个方法,其实都已经被 ReactiveFeign.Builder 重写过了。

public abstract static class Builder<T> implements ReactiveFeignBuilder<T>{

    ......

    protected InvocationHandlerFactory invocationHandlerFactory =
            new ReactiveInvocationHandler.Factory();

    protected Builder(){
          contract(new Contract.Default());
          addLoggerListener(new DefaultReactiveLogger(Clock.systemUTC()));
    }

    @Override
    public Contract contract(){
      return contract;
    }
    
     @Override
    public InvocationHandlerFactory invocationHandlerFactory(){
      return invocationHandlerFactory;
    }

    @Override
        public PublisherHttpClient create(MethodMetadata methodMetadata) {
          checkNotNull(clientFactory,
                  "clientFactory wasn't provided in ReactiveFeign builder");

          ReactiveHttpClient reactiveClient = clientFactory.create(methodMetadata);

          List<ReactiveHttpExchangeFilterFunction> exchangeFilterFunctionsAll = new ArrayList(exchangeFilterFunctions);

          if(decode404){
            exchangeFilterFunctionsAll.add(ofResponseProcessor(ResponseMappers.ignore404()));
          }

          if(statusHandler != null) {
            exchangeFilterFunctionsAll.add(ofResponseProcessor(handleStatus(statusHandler)));
          }

          for(ReactiveLoggerListener<Object> loggerListener : loggerListeners){
            exchangeFilterFunctionsAll.add(log(methodMetadata, target, loggerListener));
          }

          Optional<ReactiveHttpExchangeFilterFunction> exchangeFilterFunction = exchangeFilterFunctionsAll.stream()
                  .reduce(ReactiveHttpExchangeFilterFunction::then);
          if(exchangeFilterFunction.isPresent()){
            reactiveClient = exchangeFilterFunction.get().filter(reactiveClient);
          }

          // 根据返回值类型区分不同的PublisherHttpClient
          // 返回值是mono或者flux
          reactivefeign.publisher.PublisherHttpClient publisherClient = toPublisher(reactiveClient, methodMetadata);
          // 重试策略
          if (retryPolicy != null) {
            publisherClient = retry(publisherClient, methodMetadata, retryPolicy.toRetryFunction());
          }

          return publisherClient;
        }
      };
    }

    @Override
    public MethodHandlerFactory buildReactiveMethodHandlerFactory(PublisherClientFactory reactiveClientFactory) {
      MethodHandlerFactory methodHandlerFactory = new ReactiveMethodHandlerFactory(reactiveClientFactory);
      return fallbackFactory != null
              ? new FallbackMethodHandlerFactory(methodHandlerFactory, (Function<Throwable, Object>) fallbackFactory)
              : methodHandlerFactory;
    }

    protected PublisherHttpClient toPublisher(ReactiveHttpClient reactiveHttpClient, MethodMetadata methodMetadata){
      if(isResponsePublisher(methodMetadata.returnType())){
        return new ResponsePublisherHttpClient(reactiveHttpClient);
      }

      // 根据返回值判断返回 MonoPublisherHttpClient 或者 FluxPublisherHttpClient
      Class returnPublisherType = returnPublisherType(methodMetadata);
      if(returnPublisherType == Mono.class){
          return new MonoPublisherHttpClient(reactiveHttpClient);
      } else if(returnPublisherType == Flux.class){
        return new FluxPublisherHttpClient(reactiveHttpClient);
      } else {
        throw new IllegalArgumentException("Unknown returnPublisherType: " + returnPublisherType);
      }
    }
    ......
}

        到这里可以调用 ReactiveFeign#newInstance()

public class ReactiveFeign {

    ......

  private final Contract contract;
  private final MethodHandlerFactory methodHandlerFactory;
  private final InvocationHandlerFactory invocationHandlerFactory;

 public <T> T newInstance(Target<T> target) {
    final Map<String, MethodHandler> nameToHandler = targetToHandlersByName(target);
    // 接口中的方法和MethodHandler的对应关系
    final Map<Method, InvocationHandlerFactory.MethodHandler> methodToHandler = new LinkedHashMap<>();
    final List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<>();

    for (final Method method : target.type().getMethods()) {
      if (isDefault(method)) {
        final DefaultMethodHandler handler = new DefaultMethodHandler(method);
        defaultMethodHandlers.add(handler);
        methodToHandler.put(method, handler);
      } else {
        methodToHandler.put(method,
                nameToHandler.get(Feign.configKey(target.type(), method)));
      }
    }

    // jdk 的动态代理创建实例
    final InvocationHandler handler = invocationHandlerFactory.create(target, methodToHandler);
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
            new Class<?>[] {target.type()}, handler);

    for (final DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }

    return proxy;
  }
    ......
}

MethodHandler的创建过程

        ReactiveFeign 中的 MethodHandlerFactory 来创建 MethodHandler。

public class ReactiveMethodHandlerFactory implements MethodHandlerFactory {

    ......

	@Override
	public MethodHandler create(MethodMetadata metadata) {

		MethodHandler methodHandler = new PublisherClientMethodHandler(
				target, metadata, publisherClientFactory.create(metadata));

		if(isResponsePublisher(metadata.returnType())){
			return new MonoMethodHandler(methodHandler);
		}

		Type returnPublisherType = returnPublisherType(metadata);
		if(returnPublisherType == Mono.class){
			return new MonoMethodHandler(methodHandler);
		} else if(returnPublisherType == Flux.class) {
			return new FluxMethodHandler(methodHandler);
		} else {
			throw new IllegalArgumentException("Unknown returnPublisherType: " + returnPublisherType);
		}
	}
    ......
}

        当模板接口中的方法返回值不是 mono 或者 flux 的时候会报错。这里到PublisherClientFactory 创建 PublisherClient  的时候也会区分返回值的类型来确定 PublisherClient 的具体实现。

        整体请求的流程

        ReactiveInvocationHandler

                -> dispatch.get(method).invoke(args)
                        -> MethodHandler(返回值区分mono/flux)

                                -> PublisherClient (返回值区分mono/flux) 

                                        -> ReactiveHttpClient

                                                 -> webClient

                                                            -> 发起请求

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值