Feign源码解析之使用Hystrix

Feign源码解析之注入IOC容器
Feign源码解析之生成jdk动态代理
Feign源码解析之代理类的处理逻辑

上一篇文章讲解了在springcloud项目中feign代理类和feign方法的处理逻辑,在实际项目中,feign经常和hystrix一起使用。hystrix是一种熔断机制,当某个时间单位内错误次数达到一定比例,hystrix会认为服务出现故障,触发熔断,后续请求不再走该服务,防止引发系统错误的雪崩效应。当熔断时间错误后,hystrx会向对应服务尝试一次请求,判断服务是否恢复。
接下来我们看一下是用来hystrix后feign的代理类和处理逻辑和原来相比有哪些变化。
曾经在feign中是默认使用hystrix,虽然在后续的版本中改为了默认不使用hyxtrix,不过要想启用feign的hystrix,只需要增加配置feign.hystrix.enabled:true。另外提一点,可以通过@EnableHystrix或@EnableCircuitBreaker在整个项目中使用hystrix。
当feign中使用了hystrix,根据FeignClientsConfiguration的HystrixFeignConfiguration和FeignAutoConfiguration的HystrixFeignTargeterConfiguration可以看出,IOC容器中注入的Feign.Builder类和HystrixTargeter发生了变化。

@Configuration
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
	@Bean
	@Scope("prototype")
	@ConditionalOnMissingBean
	@ConditionalOnProperty(name = "feign.hystrix.enabled")
	public Feign.Builder feignHystrixBuilder() {
		return HystrixFeign.builder();
	}
}
@Configuration
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
protected static class HystrixFeignTargeterConfiguration {
	@Bean
	@ConditionalOnMissingBean
	public Targeter feignTargeter() {
		return new HystrixTargeter();
	}
}

从上一篇文章已经知道,Feign接口通过FeignClientFactoryBean的getObject方法委托targeter.target方法生成代理类,我们进行HystrixTargeter类的target方法。

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

可以看出分4种情况:
1.非hyxtrix的feign builder类,走feign.target方法,这种情况用于用户自定义配置的场景,后续生成动态代理的逻辑由用户自行实现。
2.FeignClient带fallback属性,走targetWithFallback方法。
首先从applicationContext中根据类型获取fallback对象,因此在设置fallback属性时要注意两点:
(1)fallback类必须注入IOC容器
(2)fallback必须实现对应的feign类。
然后将fallback封装成fallbackFactory进行处理,后续代码与targetWithFallbackFactory相同,分析targetWithFallbackFactory方法时再展开。

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);
}
private <T> T getFromContext(String fallbackMechanism, String feignClientName, FeignContext context,
								 Class<?> beanType, Class<T> targetType) {
	Object fallbackInstance = context.getInstance(feignClientName, beanType);
	if (fallbackInstance == null) {
		throw new IllegalStateException(String.format(
			"No " + fallbackMechanism + " instance of type %s found for feign client %s",
			beanType, feignClientName));
	}

	if (!targetType.isAssignableFrom(beanType)) {
		throw new IllegalStateException(
				String.format(
					"Incompatible " + fallbackMechanism + " instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
					beanType, targetType, feignClientName));
	}
	return (T) fallbackInstance;
}
public <T> T target(Target<T> target, T fallback) {
    return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null)
        .newInstance(target);
}

3.FeignClient带fallbackFactory属性,走targetWithFallbackFactory方法。
同样的,首先从application获取到targetWithFallbackFactory对象,在设置fallbackFactory时需要注意两点。
(1)fallbackFactory必须注入IOC容器
(2)fallbackFactory的create方法返回值必须是接口类型或其子类型。

private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
											Target.HardCodedTarget<T> target,
											HystrixFeign.Builder builder,
											Class<?> fallbackFactoryClass) {
	FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>)
		getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
	/* We take a sample fallback from the fallback factory to check if it returns a fallback
	that is compatible with the annotated feign interface. */
	Object exampleFallback = fallbackFactory.create(new RuntimeException());
	Assert.notNull(exampleFallback,
		String.format(
		"Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!",
			feignClientName));
	if (!target.type().isAssignableFrom(exampleFallback.getClass())) {
		throw new IllegalStateException(
			String.format(
				"Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'",
				feignClientName, exampleFallback.getClass(), target.type()));
	}
	return builder.target(target, fallbackFactory);
}
public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
   return build(fallbackFactory).newInstance(target);
}

接着看build方法,可以看出,和其父类的build方法(Feign默认的build逻辑)相比,只是修改了其InvocationHandlerFactory属性和ParseHandlersByName属性的contract属性,返回的依旧是ReflevtiveFeign方法,后续的逻辑和上一篇的feign默认的逻辑相同,不再展开。

Feign build(final FallbackFactory<?> nullableFallbackFactory) {
      super.invocationHandlerFactory(new InvocationHandlerFactory() {
        @Override public InvocationHandler create(Target target,
            Map<Method, MethodHandler> dispatch) {
          return new HystrixInvocationHandler(target, dispatch, setterFactory, nullableFallbackFactory);
        }
      });
      super.contract(new HystrixDelegatingContract(contract));
      return super.build();
    }

那么,修改了ReflevtiveFeign的InvocationHandlerFactory类型的属性会产生什么影响呢?
这一属性修改对应的是ReflectiveFeign的newInstance方法的InvocationHandler handler = factory.create(target, methodToHandler);语句的执行结果。
默认的不带hystrix的逻辑会调用InvocationHandlerFactory.Default方法得到FeignInvocationHandler类,而带hystrix的feign逻辑从上文对应invocationHandlerFactory的匿名类可以看出,返回的是HystrixInvocationHandler,代理类处理方法时的逻辑自然发生了变化。

static final class Default implements InvocationHandlerFactory {

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

修改了ReflevtiveFeign的ParseHandlersByName属性的contract属性会产生什么影响呢?
这一属性的修改对应的是ReflectiveFeign的newInstance方法的Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);语句,更细致点说对应ParseHandlersByName类的apply方法的List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());语句,由Feign方法到MethodMetaData的逻辑发生了变化。
接下来仔细看看发生了什么变化,如下文,这里的delegate对应的就是Feign中的默认Contract,因此可以看出在执行完原先Feign的处理逻辑之后,HystrixDelegatingContract又在其后进行遍历增加了对返回类型的额外判断和处理。

@Override
public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
  List<MethodMetadata> metadatas = this.delegate.parseAndValidatateMetadata(targetType);

  for (MethodMetadata metadata : metadatas) {
    Type type = metadata.returnType();

    if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(HystrixCommand.class) {
      Type actualType = resolveLastTypeParameter(type, HystrixCommand.class);
      metadata.returnType(actualType);
    } else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Observable.class)) {
      Type actualType = resolveLastTypeParameter(type, Observable.class);
      metadata.returnType(actualType);
    } else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Single.class)) {
      Type actualType = resolveLastTypeParameter(type, Single.class);
      metadata.returnType(actualType);
    } else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Completable.class)) {
      metadata.returnType(void.class);
    }
  }

  return metadatas;
}

ParameterizedType表示参数化类型,即泛型,如Collection<String>。getRawType表示对应ParameterizedType的类型,如Collection<String>的getRawType返回Collection的className。
HystrixDelegatingContract针对返回类型是泛型的方法且getRawType为hystrix中特殊类的方法做处理,getRawType为HystrixCommand、Observable、Single类型都由resolveLastTypeParameter获取到返回值,Completable返回值类型设置为void。
4.FeignClient没有设置回滚,走feign.target。
此时按fallbackFactory为null作为参数条用build方法,其它逻辑与上述的一致。

@Override
 public Feign build() {
   return build(null);
 }

二. HystrixInvocationHandler的invoke方法
最后,看一看启用了hystrix的feign对应的HystrixInvocationHandler的invoke方法,分4步:
1.对于equals、hashCode、toString的方法处理,和FeignInvocationHandler相同。
2.封装成hystrixCommand,包括执行逻辑run和回滚逻辑fallback。
run方法的执行逻辑和FeignInvocationHandler也基本一致,当然不是和FeignInvocationHandler一样简单的同步执行http请求并返回,而是交个hystrix统一管理。
fallback交给之前传入的参数fallbackFactory生成,如果fallbackFactory为null,则直接抛出异常,否则交给自定义的回滚类处理。
3.返回值为HystrixCommand、Observable、Single、Completable的特殊处理。
4.执行hystrixCommand的execute方法,

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

    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();
  }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值