Feign整合Ribbon和Hystrix源码解析

怎甘沉沦 提交于 2019-12-02 06:24:31

在上篇文章Feign自动装配中,我们提到了Feign的自动装配的原理,以及Feign整合Ribbon和Hystrix的核心在类FeignClientFactoryBean中,那么本篇文章就来揭开这个类的神秘面纱

首先,我们看到这个类实现了FactoryBean这个接口,这个接口的主要作用就是利用getObject()来创建一些实例化过程比较复杂的bean,更多关于这个接口的内容可以参考这篇文章:Spring扩展点之FactoryBean接口

我们直接来看这个类的getObject方法:

	public Object getObject() throws Exception { 		FeignContext context = applicationContext.getBean(FeignContext.class); 		Feign.Builder builder = feign(context);  		if (!StringUtils.hasText(this.url)) { 			String url; 			if (!this.name.startsWith("http")) { 				url = "http://" + this.name; 			} 			else { 				url = this.name; 			} 			url += cleanPath(); 			return 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 client = getOptional(context, Client.class); 		if (client != null) { 			if (client instanceof LoadBalancerFeignClient) { 				// not lod balancing because we have a url, 				// but ribbon is on the classpath, so unwrap 				client = ((LoadBalancerFeignClient)client).getDelegate(); 			} 			builder.client(client); 		} 		Targeter targeter = get(context, Targeter.class); 		return targeter.target(this, builder, context, new HardCodedTarget<>( 				this.type, this.name, url)); 	} 
  1. 获取bean:FeignContext,这个bean上篇文章已经说过了。里面包含了各个Feign客户端的配置
2. 构建Feign.Builder

设置编解码器

	protected Feign.Builder feign(FeignContext context) { 		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class); 		Logger logger = loggerFactory.create(this.type);  		Feign.Builder builder = get(context, Feign.Builder.class) 				.logger(logger) 				.encoder(get(context, Encoder.class)) 				.decoder(get(context, Decoder.class)) 				.contract(get(context, Contract.class)); 		configureFeign(context, builder);  		return builder; 	} 

设置日志、重试策略、错误code解析、超时时间、拦截器

	protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) { 		Logger.Level level = getOptional(context, Logger.Level.class); 		if (level != null) { 			builder.logLevel(level); 		} 		Retryer retryer = getOptional(context, Retryer.class); 		if (retryer != null) { 			builder.retryer(retryer); 		} 		ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class); 		if (errorDecoder != null) { 			builder.errorDecoder(errorDecoder); 		} 		Request.Options options = getOptional(context, Request.Options.class); 		if (options != null) { 			builder.options(options); 		} 		Map<String, RequestInterceptor> requestInterceptors = context.getInstances( 				this.name, RequestInterceptor.class); 		if (requestInterceptors != null) { 			builder.requestInterceptors(requestInterceptors.values()); 		}  		if (decode404) { 			builder.decode404(); 		} 	} 
  1. 判断Feign是否指定url属性,正常情况下是没有指定url的,所以会添加一个http://前缀
4. 获取代理
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,                             HardCodedTarget<T> target) {      Client client = getOptional(context, Client.class);     if (client != null) {         builder.client(client);         Targeter targeter = get(context, Targeter.class);          return targeter.target(this, builder, context, target);     }  	throw new IllegalStateException( 				"No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); } 

首先获取Client的实现类,这个实现类是LoadBalancerFeignClient,这个类里融合了Ribbon的相关内容。然后将Client包装到Feign.Builder中,接着获取Targeter,这里我们存在Hystrix环境,所以Targeter的实现类为HystrixTargeter

	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, 						Target.HardCodedTarget<T> target) { 		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) { 			return feign.target(target); 		} 		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign; 		SetterFactory setterFactory = getOptional(factory.getName(), context, 			SetterFactory.class); 		if (setterFactory != null) { 			builder.setterFactory(setterFactory); 		} 		Class<?> fallback = factory.getFallback(); 		if (fallback != void.class) { 			return targetWithFallback(factory.getName(), context, target, builder, fallback); 		} 		Class<?> fallbackFactory = factory.getFallbackFactory(); 		if (fallbackFactory != void.class) { 			return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory); 		}  		return feign.target(target); 	} 

接着以Feign客户端设置了fallback为例

	private <T> T targetWithFallback(String feignClientName, FeignContext context,Target.HardCodedTarget<T> target,HystrixFeign.Builder builder, Class<?> fallback) { 		T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type()); 		return builder.target(target, fallbackInstance); 	} 

接着就是这个代理的创建,现在这个代理中包含了Ribbon和Hystrix。而这个代理类的实现类是HystrixInvocationHandler

  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();     }      HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {       @Override       protected Object run() throws Exception {         try {           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 (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();   } 

这里就利用到了Hystrix的知识,更多关于Hystrix的内容可以参考之前的文章

接着深入invoke方法

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

这里构建了请求信息和重试策略,具体请求内容在下面:

Object executeAndDecode(RequestTemplate template) throws Throwable {     Request request = targetRequest(template);      if (logLevel != Logger.Level.NONE) {       logger.logRequest(metadata.configKey(), logLevel, request);     }      Response response;     long start = System.nanoTime();     try {       response = client.execute(request, options);       // ensure the request is set. TODO: remove in Feign 10       response.toBuilder().request(request).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);      boolean shouldClose = true;     try {       if (logLevel != Logger.Level.NONE) {         response =             logger.logAndRebufferResponse(metadata.configKey(), logLevel, response, elapsedTime);         // ensure the request is set. TODO: remove in Feign 10         response.toBuilder().request(request).build();       }       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 {           return decode(response);         }       } else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {         return decode(response);       } 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());       }     }   }  

再往下深入就是Ribbon的负载均衡了,具体内容可以参考之前的文章

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!