springCloud feign 源碼解析

基於NetFlix Feign實現,整合了SpringCloud Ribbon 和 SpringCloud hystrix, 同時封裝了Http調用流程,更適合面向接口化的編程習慣

該圖片摘自https://www.jianshu.com/p/8c7b92b4396c
該圖片摘自https://www.jianshu.com/p/8c7b92b4396c

以下解析源自版本
springBoot 2.1.3.RELEASE
springCloud Greenwich.RELEASE

一、快速入門

maven

		<!--客戶端eureka註冊-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--使用feign、包含ribbon、hystrix整合-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

服務接口

/**
 * 此接口是由serverId爲car的服務暴露和實現,通過eureka、@RequestMapping等獲取具體的請求ip和請求路徑
 */
@FeignClient("car")
@RequestMapping("/car")
public interface CarClient {

    @GetMapping("/getCarNo")
    ResultModelDTO<String> getCarNo();


    @GetMapping("/getCarNoQuery")
    ResultModelDTO<String> getCarNoQuery(@RequestParam("carNo") String carNo);
}

請求方

@SpringBootApplication
@EnableDiscoveryClient //eureka客戶端註冊
@EnableFeignClients("com.zkml")//支持feign
public class CarFacadeApplication {

    public static void main(String[] args) {
        SpringApplication.run(CarFacadeApplication.class, args);
    }
}

@RestController
public class TestFeignController {

    @Autowired
    CarClient carClient;

    @RequestMapping("/getCarNoQuery")
    public ResultModelDTO<String> getCarNoQuery(String carNo){
        return carClient.getCarNoQuery(carNo);
    }
}

服務方

@RestController
public class CarController implements CarClient{

    public ResultModelDTO<String> getCarNo(){
        return ResultModelUtil.successResult("皖123456");
    }

    @Override
    public ResultModelDTO<String> getCarNoQuery(String carNo) {
        return ResultModelUtil.successResult(carNo);
    }
}

二、源碼解析

1、掃描注入FeignClient註解接口

在請求方的啓動類上有一個@EnableFeignClients註解,表示啓用feign

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
	//略
}

主要掃描注入邏輯在FeignClientsRegistrar,這個類實現了ImportBeanDefinitionRegistrar接口, springBoot會調用registerBeanDefinitions方法動態注入bean https://blog.csdn.net/yzqingqing/article/details/88537333

	
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		//如果在@EnableFeignClients中配置了defaultConfiguration,則在這裏進行處理
		//包裝成FeignClientSpecification類進行注入
		registerDefaultConfiguration(metadata, registry);
		//1、根據@EnableFeignClients中配置的value、basePackages、basePackageClasses、clients掃描相應的包,獲取@FeignClient註解的接口集合
		//2、把目標接口名稱以及@FeignClient各項參數包裝成FeignClientFactoryBean類進行注入
		registerFeignClients(metadata, registry);
	}

	public void registerFeignClients(AnnotationMetadata metadata,
			BeanDefinitionRegistry registry) {
		
		//略去部分代碼
		
		for (String basePackage : basePackages) {
			Set<BeanDefinition> candidateComponents = scanner
					.findCandidateComponents(basePackage);
			for (BeanDefinition candidateComponent : candidateComponents) {
				if (candidateComponent instanceof AnnotatedBeanDefinition) {
					// verify annotated class is an interface
					AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
					AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
					Assert.isTrue(annotationMetadata.isInterface(),
							"@FeignClient can only be specified on an interface");

					Map<String, Object> attributes = annotationMetadata
							.getAnnotationAttributes(
									FeignClient.class.getCanonicalName());
					//這裏的name依次根據contextId、value、name、serviceId獲取
					String name = getClientName(attributes);
					//FeignClient的配置類包裝成FeignClientSpecification類進行注入
					registerClientConfiguration(registry, name,
							attributes.get("configuration"));
					//注入目標接口
					registerFeignClient(registry, annotationMetadata, attributes);
				}
			}
		}
	}

	//把目標接口名稱以及@FeignClient各項參數包裝成FeignClientFactoryBean類進行注入
	private void registerFeignClient(BeanDefinitionRegistry registry,
			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
		//基於FeignClientFactoryBean創建bean,根據@FeignClient設置相應配置屬性
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		definition.addPropertyValue("url", getUrl(attributes));
		definition.addPropertyValue("path", getPath(attributes));
		//這裏的name依次根據serviceId、name、value獲取
		String name = getName(attributes);
		definition.addPropertyValue("name", name);
		String contextId = getContextId(attributes);
		definition.addPropertyValue("contextId", contextId);
		//這裏的className爲目標接口類名稱
		definition.addPropertyValue("type", className);
		definition.addPropertyValue("decode404", attributes.get("decode404"));
		definition.addPropertyValue("fallback", attributes.get("fallback"));
		definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

		String alias = contextId + "FeignClient";
		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();

		boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null

		//如果多個@FeignClient存在並且name相同,可以設置@FeignClient(value = "car",primary = false)
		beanDefinition.setPrimary(primary);

		String qualifier = getQualifier(attributes);
		if (StringUtils.hasText(qualifier)) {
			alias = qualifier;
		}

		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		//注入
		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
	}

2、FeignContext

feign的一個上下文環境類,根據clientName創建不同的spring ApplicationContext,並從中註冊或者獲取屬於這個clientName的bean,有效的隔離了不同clientName之間的相互影響

public class FeignContext extends NamedContextFactory<FeignClientSpecification> {

	public FeignContext() {
		super(FeignClientsConfiguration.class, "feign", "feign.client.name");
	}

}

FeignContext繼承了NamedContextFactory

public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
		implements DisposableBean, ApplicationContextAware {

	//多個child context的集合,相互間隔離,可以根據key獲取相應的上下文環境
	private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
	//同上,這裏可以存儲多個隔離的配置類,根據key獲取相應的配置類
	private Map<String, C> configurations = new ConcurrentHashMap<>();

	//根據name從contexts中獲取相應的context,並且從中取出bean
	public <T> Map<String, T> getInstances(String name, Class<T> type) {
		AnnotationConfigApplicationContext context = getContext(name);
		if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,
				type).length > 0) {
			return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
		}
		return null;
	}

	//根據name獲取context的方法,如果contexts中沒有相應的context,創建一個
	protected AnnotationConfigApplicationContext getContext(String name) {
		if (!this.contexts.containsKey(name)) {
			synchronized (this.contexts) {
				if (!this.contexts.containsKey(name)) {
					this.contexts.put(name, createContext(name));
				}
			}
		}
		return this.contexts.get(name);
	}

	//其它方法 略
}

在FeignAutoConfiguration中,springCloud注入了FeignContext

@Configuration
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class})
public class FeignAutoConfiguration {

	//FeignClientsRegistrar類中動態注入的FeignClientSpecification,在這裏可以獲取到
	//FeignClientSpecification中包裝了@FeignClient或@EnableFeignClients的配置類
	//詳細看上文中的(1、掃描注入FeignClient註解接口)
	@Autowired(required = false)
	private List<FeignClientSpecification> configurations = new ArrayList<>();

	//這裏注入FeignContext
	@Bean
	public FeignContext feignContext() {
		FeignContext context = new FeignContext();
		context.setConfigurations(this.configurations);
		return context;
	}
	//省略不重要的代碼
}

3、Feign.Builder

Feign用到了建造者模式,所以有一個Builder類負責設置參數以及構建目標類

public static class Builder {

    private final List<RequestInterceptor> requestInterceptors =
        new ArrayList<RequestInterceptor>();
    //設置feign日誌級別
    private Logger.Level logLevel = Logger.Level.NONE;
    //解析目標接口的註解 springCloud默認使用SpringMvcContract
    private Contract contract = new Contract.Default();
    //http請求類,springCloud默認使用LoadBalancerFeignClient
    private Client client = new Client.Default(null, null);
    //重試策略類
    private Retryer retryer = new Retryer.Default();
    //日誌類,springCloud默認使用Slf4jLogger
    private Logger logger = new NoOpLogger();
    //對傳輸的內容進行編碼,springCloud默認使用SpringEncoder
    private Encoder encoder = new Encoder.Default();
    //對返回的內容進行解碼,springCloud默認使用SpringDecoder
    private Decoder decoder = new Decoder.Default();
    //將object對象轉換成map的處理類
    private QueryMapEncoder queryMapEncoder = new QueryMapEncoder.Default();
    //對失敗的http請求進行解碼
    private ErrorDecoder errorDecoder = new ErrorDecoder.Default();
    //http請求參數類,包含connectTimeoutMillis、readTimeoutMillis、是否處理重定向
    private Options options = new Options();
    //生成InvocationHandler處理類
    //Feign通過這種方式加入了hytrix的熔斷功能,詳細看feign.hystrix.HystrixFeign.Builder#build
    private InvocationHandlerFactory invocationHandlerFactory =
        new InvocationHandlerFactory.Default();
    //是否解碼404結果
    private boolean decode404;
    //是否在發起請求後關閉本次鏈接
    private boolean closeAfterDecode = true;
    private ExceptionPropagationPolicy propagationPolicy = NONE;


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

	//創建了ParseHandlersByName、SynchronousMethodHandler.Factory 並且用ReflectiveFeign進行包裝
	//ParseHandlersByName 負責調用Contract類解析接口方法以及註解、調用SynchronousMethodHandler.Factory將接口方法包裝成MethodHandler進行內部處理
	//SynchronousMethodHandler 實現MethodHandler接口,對目標接口方法進行攔截,實現具體的http遠程請求
    public Feign build() {
      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
              logLevel, decode404, closeAfterDecode, propagationPolicy);
      ParseHandlersByName handlersByName =
          new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
              errorDecoder, synchronousMethodHandlerFactory);
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }

//******************下面都是配置操作***********************//

    public Builder logLevel(Logger.Level logLevel) {
      this.logLevel = logLevel;
      return this;
    }

    public Builder contract(Contract contract) {
      this.contract = contract;
      return this;
    }

    public Builder client(Client client) {
      this.client = client;
      return this;
    }

    public Builder retryer(Retryer retryer) {
      this.retryer = retryer;
      return this;
    }

    public Builder logger(Logger logger) {
      this.logger = logger;
      return this;
    }

    public Builder encoder(Encoder encoder) {
      this.encoder = encoder;
      return this;
    }

    public Builder decoder(Decoder decoder) {
      this.decoder = decoder;
      return this;
    }

    public Builder queryMapEncoder(QueryMapEncoder queryMapEncoder) {
      this.queryMapEncoder = queryMapEncoder;
      return this;
    }

  
    public Builder mapAndDecode(ResponseMapper mapper, Decoder decoder) {
      this.decoder = new ResponseMappingDecoder(mapper, decoder);
      return this;
    }

   
    public Builder decode404() {
      this.decode404 = true;
      return this;
    }

    public Builder errorDecoder(ErrorDecoder errorDecoder) {
      this.errorDecoder = errorDecoder;
      return this;
    }

    public Builder options(Options options) {
      this.options = options;
      return this;
    }

   
    public Builder requestInterceptor(RequestInterceptor requestInterceptor) {
      this.requestInterceptors.add(requestInterceptor);
      return this;
    }

   
    public Builder requestInterceptors(Iterable<RequestInterceptor> requestInterceptors) {
      this.requestInterceptors.clear();
      for (RequestInterceptor requestInterceptor : requestInterceptors) {
        this.requestInterceptors.add(requestInterceptor);
      }
      return this;
    }

   
    public Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
      this.invocationHandlerFactory = invocationHandlerFactory;
      return this;
    }

   
    public Builder doNotCloseAfterDecode() {
      this.closeAfterDecode = false;
      return this;
    }

    public Builder exceptionPropagationPolicy(ExceptionPropagationPolicy propagationPolicy) {
      this.propagationPolicy = propagationPolicy;
      return this;
    }
  }

4、Client

負責發送http請求的接口類,實現類需要遵守線程安全

public interface Client {
	//執行http請求,返回Response
	Response execute(Request request, Options options) throws IOException;
}

feign支持okhttp、httpclient,
默認情況下使用的java的 java.net.HttpURLConnection,並且沒有連接池,性能較低
在FeignRibbonClientAutoConfiguration中引入了HttpClientFeignLoadBalancedConfiguration.class、OkHttpFeignLoadBalancedConfiguration.class、
DefaultFeignLoadBalancedConfiguration.class
分別提供支持httpclient、okhttp、HttpURLConnection的Client.class

@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@Configuration
@AutoConfigureBefore(FeignAutoConfiguration.class)
@EnableConfigurationProperties({ FeignHttpClientProperties.class })
@Import({ HttpClientFeignLoadBalancedConfiguration.class, //httpclient支持
		OkHttpFeignLoadBalancedConfiguration.class, //okhttp支持
		DefaultFeignLoadBalancedConfiguration.class }) //HttpURLConnection
public class FeignRibbonClientAutoConfiguration {

	//略
}

HttpClientFeignLoadBalancedConfiguration.class

		@Bean
		@ConditionalOnProperty(value = "feign.compression.response.enabled", havingValue = "false", matchIfMissing = true)
		public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory, HttpClientConnectionManager httpClientConnectionManager,
											  FeignHttpClientProperties httpClientProperties) {
			//創建CloseableHttpClient對象
			this.httpClient = createClient(httpClientFactory.createBuilder(), httpClientConnectionManager, httpClientProperties);
			return this.httpClient;
		}


		@Bean
		@ConditionalOnMissingBean(Client.class)
		public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
								  SpringClientFactory clientFactory, HttpClient httpClient) {
			//將上面創建的CloseableHttpClient對象設置到ApacheHttpClient中
			ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
			return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
		}

OkHttpFeignLoadBalancedConfiguration.class

		@Bean
		public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
										   ConnectionPool connectionPool, FeignHttpClientProperties httpClientProperties) {
			Boolean followRedirects = httpClientProperties.isFollowRedirects();
			Integer connectTimeout = httpClientProperties.getConnectionTimeout();
			//創建okhttp3.OkHttpClient對象
			this.okHttpClient = httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).
					connectTimeout(connectTimeout, TimeUnit.MILLISECONDS).
					followRedirects(followRedirects).
					connectionPool(connectionPool).build();
			return this.okHttpClient;
		}

	@Bean
	@ConditionalOnMissingBean(Client.class)
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
							  SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
		OkHttpClient delegate = new OkHttpClient(okHttpClient);
		return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
	}

DefaultFeignLoadBalancedConfiguration.class

	@Bean
	@ConditionalOnMissingBean
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
							  SpringClientFactory clientFactory) {
		//使用feign默認的client  Client.Default
		return new LoadBalancerFeignClient(new Client.Default(null, null),
				cachingFactory, clientFactory);
	}

啓用httpclient

		<!--pom.xml-->
		<!--這裏的version要和feign-core保持一致-->
		<dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>10.1.0</version>
        </dependency>

啓用okhttp

		<!--pom.xml-->
		<!--這裏的version要和feign-core保持一致-->
		<dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
            <version>10.1.0</version>
        </dependency>
##禁用httpclient
feign.httpclient.enabled=false
##啓用okhttp
feign.okhttp.enabled=true

5、FeignClientFactoryBean 動態代理

在第一部分(1、掃描注入FeignClient註解接口) 中講到在FeignClientsRegistrar實現動態注入,將目標接口類包裝成FeignClientFactoryBean

FeignClientFactoryBean實現了FactoryBean接口,也就是說FeignClientFactoryBean是一個bean工廠,通過調用getObject方法提供目標接口的實現類

	//請求方通過@Autowired獲取目標接口的實現類,實際是調用FeignClientFactoryBean.getObject()
 	@Autowired
    CarClient carClient;

	class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
		ApplicationContextAware {
		@Override
		public Object getObject() throws Exception {
			return getTarget();
		}
	}

	//基於java的面向接口的動態代理方式生成目標接口的實現類
	<T> T getTarget() {
		//獲取Feign的上下文環境,詳細看上文(2、FeignContext)
		FeignContext context = applicationContext.getBean(FeignContext.class);
		//根據上下文環境構建Builder類,填充參數配置
		Feign.Builder builder = feign(context);
		//這裏會對url進行構建,針對上文的例子@FeignClient("car"),url會構建成http://car
		if (!StringUtils.hasText(this.url)) {
			if (!this.name.startsWith("http")) {
				url = "http://" + this.name;
			}
			else {
				url = this.name;
			}
			url += cleanPath();
			return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
					this.name, url));
		}
		if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
			this.url = "http://" + this.url;
		}
		String url = this.url + cleanPath();
		//在當前上下文環境中獲取Client類型實例,如果用到了ribbon,這裏的Client會獲取到LoadBalancerFeignClient
		Client client = getOptional(context, Client.class);
		if (client != null) {
			if (client instanceof LoadBalancerFeignClient) {
				// not load balancing because we have a url,
				// but ribbon is on the classpath, so unwrap
				client = ((LoadBalancerFeignClient)client).getDelegate();
			}
			builder.client(client);
		}
		//如果引入了hytrix,這裏會獲取到HystrixTargeter,主要邏輯
		//1、定義HystrixCommandKey(CarClient#getCarNoQuery(String))、HystrixCommandGroupKey(car)
		//2、對fallback、fallbackFactory進行處理
		//3、在builder中加入InvocationHandlerFactory工廠創建HystrixInvocationHandler,在目標接口調用時加入hytrix的熔斷功能
		//4、最終調用ReflectiveFeign.newInstance(Target<T> target)生成實現類
		Targeter targeter = get(context, Targeter.class);
		return (T) targeter.target(this, builder, context, new HardCodedTarget<>(
				this.type, this.name, url));
	}

ReflectiveFeign繼承了Feign, 通過builder創建,主要邏輯是對目標接口方法進行解析包裝,加入攔截器,最終生成實現類

@SuppressWarnings("unchecked")
  @Override
  public <T> T newInstance(Target<T> target) {
  //這裏的targetToHandlersByName就是ParseHandlersByName類,具體看(3、Feign.Builder)
  //關鍵點1
    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;
      //對接口中的default方法進行處理
      } 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)));
      }
    }
    //如果引入了hytrix,這裏會創建HystrixInvocationHandler,在這裏加入熔斷
    //關鍵點2
    InvocationHandler handler = factory.create(target, methodToHandler);
    //java基於接口的動態代理,當方法被調用時,轉發給handler進行處理
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

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

在上述代碼中有幾個關鍵的地方
1、ParseHandlersByName處理目標類,最終將目標類的方法包裝成MethodHandler

//feign.ReflectiveFeign.ParseHandlersByName.java
public Map<String, MethodHandler> apply(Target key) {
	//Contract協議,對目標類方法上的註解進行解析,包裝成MethodMetadata
      List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
      Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
      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);
        }
        //這裏是SynchronousMethodHandler.Factory,最終將方法包裝成SynchronousMethodHandler
        //在這個方法內部實現了request包裝、encode編碼、請求攔截、調用client做http請求、對返回的response做decoder解碼等
        result.put(md.configKey(),
            factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
      }
      return result;
    }

2、HystrixInvocationHandler對代理方法調用的處理

final class HystrixInvocationHandler implements InvocationHandler {

  private final Target<?> target;
  private final Map<Method, MethodHandler> dispatch;
  private final FallbackFactory<?> fallbackFactory; // Nullable
  private final Map<Method, Method> fallbackMethodMap;
  private final Map<Method, Setter> setterMethodMap;

  HystrixInvocationHandler(Target<?> target, Map<Method, MethodHandler> dispatch,
      SetterFactory setterFactory, FallbackFactory<?> fallbackFactory) {
    this.target = checkNotNull(target, "target");
    this.dispatch = checkNotNull(dispatch, "dispatch");
    this.fallbackFactory = fallbackFactory;
    this.fallbackMethodMap = toFallbackMethod(dispatch);
    this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet());
  }
@Override
  public Object invoke(final Object proxy, final Method method, final Object[] args)
      throws Throwable {
    // early exit if the invoked method is from java.lang.Object
    // code is the same as ReflectiveFeign.FeignInvocationHandler
    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();
    }
	//在這裏加入了hystrix熔斷功能
    HystrixCommand<Object> hystrixCommand =
        new HystrixCommand<Object>(setterMethodMap.get(method)) {
          @Override
          protected Object run() throws Exception {
            try {
              //這裏實際調用了SynchronousMethodHandler.invoke
              return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
            } catch (Exception e) {
              throw e;
            } catch (Throwable t) {
              throw (Error) t;
            }
          }

          @Override
          protected Object getFallback() {
            if (fallbackFactory == null) {
              return super.getFallback();
            }
            try {
              Object fallback = fallbackFactory.create(getExecutionException());
              Object result = fallbackMethodMap.get(method).invoke(fallback, args);
              if (isReturnsHystrixCommand(method)) {
                return ((HystrixCommand) result).execute();
              } else if (isReturnsObservable(method)) {
                // Create a cold Observable
                return ((Observable) result).toBlocking().first();
              } else if (isReturnsSingle(method)) {
                // Create a cold Observable as a Single
                return ((Single) result).toObservable().toBlocking().first();
              } else if (isReturnsCompletable(method)) {
                ((Completable) result).await();
                return null;
              } else {
                return result;
              }
            } catch (IllegalAccessException e) {
              // shouldn't happen as method is public due to being an interface
              throw new AssertionError(e);
            } catch (InvocationTargetException e) {
              // Exceptions on fallback are tossed by Hystrix
              throw new AssertionError(e.getCause());
            }
          }
        };

    if (Util.isDefault(method)) {
      return hystrixCommand.execute();
    } else if (isReturnsHystrixCommand(method)) {
      return hystrixCommand;
    } else if (isReturnsObservable(method)) {
      // Create a cold Observable
      return hystrixCommand.toObservable();
    } else if (isReturnsSingle(method)) {
      // Create a cold Observable as a Single
      return hystrixCommand.toObservable().toSingle();
    } else if (isReturnsCompletable(method)) {
      return hystrixCommand.toObservable().toCompletable();
    }
    return hystrixCommand.execute();
  }
}

6、SynchronousMethodHandler

@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) {
        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) throws Throwable {
	//進一步包裝成Request對象
    Request request = targetRequest(template);
	//根據日誌級別打印不同詳細程度的日誌
    if (logLevel != Logger.Level.NONE) {
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
      //如果引入了ribbon,這裏的client的實現類是LoadBalancerFeignClient
      //將會對請求服務進行負載算法,選出一個地址,並且調用最終的http請求框架,例如httpClient、okhttp
      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 {
          //對返回的結果進行解碼處理,這裏默認調用springDecode
          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());
      }
    }
  }

7、Contract協議
用來解析接口方法、參數以及註解的協議
在這裏插入圖片描述
該圖片摘自https://www.jianshu.com/p/8c7b92b4396c

public interface Contract {
	  List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);
}

Contract內部提供了一個抽象類BaseContract,做了一些基礎的處理,以及定義了三個抽象方法方便子類進行功能擴展

abstract class BaseContract implements Contract{
	//略去多餘代碼

	//對目標class上的註解進行解析
    protected abstract void processAnnotationOnClass(MethodMetadata data, Class<?> clz);

    //對目標方法上的註解進行解析
    protected abstract void processAnnotationOnMethod(MethodMetadata data,
                                                      Annotation annotation,
                                                      Method method);
	
	//對目標方法的傳參上的註解進行解析
    protected abstract boolean processAnnotationsOnParameter(MethodMetadata data,
                                                             Annotation[] annotations,
                                                             int paramIndex);
}

feign基於BaseContract 在Contract內部實現了一個默認的解析協議Default,使用了他自己定義的註解
但是基於學習成本以及大家的使用習慣,springCloud基於BaseContract實現了SpringMvcContract,可以使用部分springMvc的註解,支持@RequestMapping、@PathVariable、@RequestHeader、@RequestParam
如果參數不加註解,默認按照requestBody去處理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章