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去处理

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值