feign源码解析--fegin的执行过程

一执行逻辑

通过上篇文章分析我们知道,fegin客户端在初始化的时候,会通过jdk动态代理未为每个feignClient生成一个代理类,jdk动态代理主要是通过InvocationHandler接口的实现代理的增强.我们来看看生成代理时InvocationHandler接口的实现是如何创建的

// 通过InvocationHandlerFactory创建InvocationHandlerFactory
InvocationHandler handler = factory.create(target, methodToHandler);
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

通过InvocationHandlerFactory 我们可以发现创建的是ReflectiveFeign.FeignInvocationHandler,通过ReflectiveFeign.FeignInvocationHandler来实现动态代理的底层逻辑

public interface InvocationHandlerFactory {

  InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);

  /**
   * Like {@link InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])}, except for a
   * single method.
   */
  interface MethodHandler {

    Object invoke(Object[] argv) throws Throwable;
  }

  static final class Default implements InvocationHandlerFactory {

    @Override
    public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
      return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
    }
  }
}

我们可以来看看ReflectiveFeign.FeignInvocationHandler底层是如何处理的,主要是InvocationHandler接口的invoke()的实现
我们可以看到这里主要是对equals和hashCode等的处理,最终会如何处理呢,通过断点我们发现最终会调用SynchronousMethodHandler来实现逻辑的增强处理

@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);
    }

那我们看看SynchronousMethodHandler做了那些处理

@Override
  public Object invoke(Object[] argv) throws Throwable {
  	// 根据方法参数转换成一个标准的RequestTemplate 
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    // 将参数转换成一个相应选项
    Options options = findOptions(argv);
    // 获得fegin的重试相关数据
    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;
      }
    }
  }

executeAndDecode方法是如何出现处理的呢

  • fegin拦截器相关执行
  • 调用RetryableFeignBlockingLoadBalancerClient处理请求
  • 异步解析和响应解析
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
	// 调用fegin所有的拦截器,并执行里面的相关逻辑 将template转换为feign内部的request
    Request request = targetRequest(template);

	// 打印日志
    if (logLevel != Logger.Level.NONE) {
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
    	// 调用RetryableFeignBlockingLoadBalancerClient进行处理
      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;
    }
  }
Request targetRequest(RequestTemplate template) {
	// 遍历所有的拦截器,执行拦截中响应的业务逻辑
    for (RequestInterceptor interceptor : requestInterceptors) {
      interceptor.apply(template);
    }
    return target.apply(template);
  }

在RetryableFeignBlockingLoadBalancerClient中的excute主要做了那些处理呢

  • 更具现有的负载均衡策略,实现客户端的负载均衡
  • 通过http的相关代理实现最终的请求
@Override
	public Response execute(Request request, Request.Options options) throws IOException {
		//  获得URI 
		final URI originalUri = URI.create(request.url());
		// 获取客户端id
		String serviceId = originalUri.getHost();
		Assert.state(serviceId != null, "Request URI does not contain a valid hostname: " + originalUri);
		final LoadBalancedRetryPolicy retryPolicy = loadBalancedRetryFactory.createRetryPolicy(serviceId,
				loadBalancerClient);
		// 构建重试retryTemplate 
		RetryTemplate retryTemplate = buildRetryTemplate(serviceId, request, retryPolicy);
		return retryTemplate.execute(context -> {
			Request feignRequest = null;
			ServiceInstance retrievedServiceInstance = null;
			Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
					.getSupportedLifecycleProcessors(
							loadBalancerClientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
							RetryableRequestContext.class, ResponseData.class, ServiceInstance.class);
			String hint = getHint(serviceId);
			DefaultRequest<RetryableRequestContext> lbRequest = new DefaultRequest<>(
					new RetryableRequestContext(null, buildRequestData(request), hint));
			// On retries the policy will choose the server and set it in the context
			// and extract the server and update the request being made
			if (context instanceof LoadBalancedRetryContext) {
				LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
				ServiceInstance serviceInstance = lbContext.getServiceInstance();
				if (serviceInstance == null) {
					if (LOG.isDebugEnabled()) {
						LOG.debug("Service instance retrieved from LoadBalancedRetryContext: was null. "
								+ "Reattempting service instance selection");
					}
					ServiceInstance previousServiceInstance = lbContext.getPreviousServiceInstance();
					lbRequest.getContext().setPreviousServiceInstance(previousServiceInstance);
					supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
					// 根据当前请求的服务id实现客户端的负载均衡
					retrievedServiceInstance = loadBalancerClient.choose(serviceId, lbRequest);
					if (LOG.isDebugEnabled()) {
						LOG.debug(String.format("Selected service instance: %s", retrievedServiceInstance));
					}
					lbContext.setServiceInstance(retrievedServiceInstance);
				}

				if (retrievedServiceInstance == null) {
					if (LOG.isWarnEnabled()) {
						LOG.warn("Service instance was not resolved, executing the original request");
					}
					org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse = new DefaultResponse(
							retrievedServiceInstance);
					supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
							.onComplete(new CompletionContext<ResponseData, ServiceInstance, RetryableRequestContext>(
									CompletionContext.Status.DISCARD, lbRequest, lbResponse)));
					feignRequest = request;
				}
				else {
					if (LOG.isDebugEnabled()) {
						LOG.debug(String.format("Using service instance from LoadBalancedRetryContext: %s",
								retrievedServiceInstance));
					}
					String reconstructedUrl = loadBalancerClient.reconstructURI(retrievedServiceInstance, originalUri)
							.toString();
					feignRequest = buildRequest(request, reconstructedUrl);
				}
			}
			org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse = new DefaultResponse(
					retrievedServiceInstance);
			// 通过http的相关代理实现最终的请求
			Response response = LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(delegate, options,
					feignRequest, lbRequest, lbResponse, supportedLifecycleProcessors,
					retrievedServiceInstance != null);
			int responseStatus = response.status();
			if (retryPolicy != null && retryPolicy.retryableStatusCode(responseStatus)) {
				if (LOG.isDebugEnabled()) {
					LOG.debug(String.format("Retrying on status code: %d", responseStatus));
				}
				response.close();
				throw new RetryableStatusCodeException(serviceId, responseStatus, response, URI.create(request.url()));
			}
			return response;
		}, new LoadBalancedRecoveryCallback<Response, Response>() {
			@Override
			protected Response createResponse(Response response, URI uri) {
				return response;
			}
		});
	}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`feign-spring-mvc-starter` 是一个 Feign 的扩展,它支持使用 Spring MVC 注解来定义和调用 REST 服务。使用 `feign-spring-mvc-starter`,你可以像使用 Spring MVC 控制器一样定义 Feign 客户端,从而更方便地进行 REST 服务的开发。 在使用 `feign-spring-mvc-starter` 之前,你需要先了解 FeignSpring MVC 的基本概念和用法。 Feign 是一个声明式的 Web 服务客户端,它可以帮助你更方便地定义和调用 REST 服务。Feign 的基本使用方法是定义一个接口,用于描述 REST 服务的 API,然后使用 Feign 注解来声明这个接口。 Spring MVC 是一个基于 Java 的 Web 框架,它提供了一组注解和 API,用于处理 Web 请求和响应。 `feign-spring-mvc-starter` 将 FeignSpring MVC 结合起来,使你可以使用 Spring MVC 注解来定义和调用 REST 服务。使用 `feign-spring-mvc-starter`,你可以更方便地使用 Feign 来调用 REST 服务。 以下是一个使用 `feign-spring-mvc-starter` 的示例: 1. 添加 Maven 依赖 在 pom.xml 文件中添加以下依赖项: ```xml <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-spring-mvc</artifactId> <version>5.3.1</version> </dependency> ``` 2. 定义 Feign 接口 定义一个 Feign 接口,用于描述 REST 服务的 API。例如: ```java @FeignClient(name = "example-service") public interface ExampleClient { @GetMapping("/example") String getExample(); } ``` 在这个接口中,我们使用了 `@FeignClient` 注解来声明这个接口是一个 Feign 客户端,并指定了服务的名称。然后,我们定义了一个 `getExample()` 方法,用于调用 example-service 服务的 /example 路径。 3. 定义 Spring MVC 控制器 定义一个 Spring MVC 控制器,用于处理来自客户端的请求。例如: ```java @RestController public class ExampleController { private final ExampleClient exampleClient; public ExampleController(ExampleClient exampleClient) { this.exampleClient = exampleClient; } @GetMapping("/") public String index() { return exampleClient.getExample(); } } ``` 在这个控制器中,我们注入了 `ExampleClient`,并在 `index()` 方法中使用它来调用 example-service 服务的 /example 路径。 4. 运行应用程序 现在,你可以运行应用程序并访问 http://localhost:8080/ ,你应该会看到来自 example-service 服务的响应。 这就是一个使用 `feign-spring-mvc-starter` 的示例。使用 `feign-spring-mvc-starter`,你可以更方便地使用 Feign 来调用 REST 服务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值