Spring OpenFeign源码分析(4) Hytrix和Sentinel

Feign与Hytrix、Sentinel集成最大的不同在于使用不同的InvocationHandlerFactory工厂:

  • 默认使用feign.InvocationHandlerFactory.Default
  • Hytrix、Sentinel分别有各自的InvocationHandlerFactory实现类

本文重点分析Hytrix、Sentinel的InvocationHandlerFactory和InvocationHandler实现逻辑。

Hytrix

feign.hystrix.enabled配置为true时会使用Hytrix相关实现类创建代理。

HystrixTargeter - 设置fallback配置

加载fallback和fallbackFactory配置,然后调用Feign.Builder创建代理:

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;
	String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
			: factory.getContextId();
	SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
	if (setterFactory != null) {
		builder.setterFactory(setterFactory);
	}
    // 加载fallback
	Class<?> fallback = factory.getFallback();
	if (fallback != void.class) {
		return targetWithFallback(name, context, target, builder, fallback);
	}
    // 加载fallbackFactory
	Class<?> fallbackFactory = factory.getFallbackFactory();
	if (fallbackFactory != void.class) {
		return targetWithFallbackFactory(name, context, target, builder,
				fallbackFactory);
	}

    // 创建代理
	return feign.target(target);
}

HystrixFeign.Builder设置InvocationHandlerFactory

这个类继承了Feign.Builder类,重写类build方法设置Hystrix使用InvocationHandlerFactory工厂实现:

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

HystrixInvocationHandler代理处理器

public Object invoke(final Object proxy, final Method method, final Object[] args)
    throws Throwable {

  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)) {
              return ((Observable) result).toBlocking().first();
            } else if (isReturnsSingle(method)) {
              return ((Single) result).toObservable().toBlocking().first();
            } else if (isReturnsCompletable(method)) {
              ((Completable) result).await();
              return null;
            } else if (isReturnsCompletableFuture(method)) {
              return ((Future) result).get();
            } else {
              return result;
            }
          } catch (IllegalAccessException e) {
            throw new AssertionError(e);
          } catch (InvocationTargetException | ExecutionException e) {
            throw new AssertionError(e.getCause());
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new AssertionError(e.getCause());
          }
        }
      };

  if (Util.isDefault(method)) {
    return hystrixCommand.execute();
  } else if (isReturnsHystrixCommand(method)) {
    return hystrixCommand;
  } else if (isReturnsObservable(method)) {
    return hystrixCommand.toObservable();
  } else if (isReturnsSingle(method)) {
    return hystrixCommand.toObservable().toSingle();
  } else if (isReturnsCompletable(method)) {
    return hystrixCommand.toObservable().toCompletable();
  } else if (isReturnsCompletableFuture(method)) {
    return new ObservableCompletableFuture<>(hystrixCommand);
  }
  return hystrixCommand.execute();
}

Sentinel

SentinelFeign.Builder设置InvocationHandlerFactory

public Feign build() {
    // 设置InvocationHandlerFactory
	super.invocationHandlerFactory(new InvocationHandlerFactory() {
		@Override
		public InvocationHandler create(Target target,
				Map<Method, MethodHandler> dispatch) {
			// using reflect get fallback and fallbackFactory properties from
			// FeignClientFactoryBean because FeignClientFactoryBean is a package
			// level class, we can not use it in our package
			Object feignClientFactoryBean = Builder.this.applicationContext
					.getBean("&" + target.type().getName());

            // 加载设置fallback和fallbackFactory
			Class fallback = (Class) getFieldValue(feignClientFactoryBean,
					"fallback");
			Class fallbackFactory = (Class) getFieldValue(feignClientFactoryBean,
					"fallbackFactory");
			String beanName = (String) getFieldValue(feignClientFactoryBean,
					"contextId");
			if (!StringUtils.hasText(beanName)) {
				beanName = (String) getFieldValue(feignClientFactoryBean, "name");
			}

			Object fallbackInstance;
			FallbackFactory fallbackFactoryInstance;
			// check fallback and fallbackFactory properties
			if (void.class != fallback) {
				fallbackInstance = getFromContext(beanName, "fallback", fallback,
						target.type());
				return new SentinelInvocationHandler(target, dispatch,
						new FallbackFactory.Default(fallbackInstance));
			}
			if (void.class != fallbackFactory) {
				fallbackFactoryInstance = (FallbackFactory) getFromContext(
						beanName, "fallbackFactory", fallbackFactory,
						FallbackFactory.class);
				return new SentinelInvocationHandler(target, dispatch,
						fallbackFactoryInstance);
			}
            // 创建代理处理器
			return new SentinelInvocationHandler(target, dispatch);
		}

		private Object getFromContext(String name, String type,
				Class fallbackType, Class targetType) {
			Object fallbackInstance = feignContext.getInstance(name,
					fallbackType);
			if (fallbackInstance == null) {
				throw new IllegalStateException("...");
			}

			if (!targetType.isAssignableFrom(fallbackType)) {
				throw new IllegalStateException("...");
			}
			return fallbackInstance;
		}
	});

	super.contract(new SentinelContractHolder(contract));
    // 创建代理
	return super.build();
}

SentinelInvocationHandler代理处理器

public Object invoke(final Object proxy, final Method method, final Object[] args)
		throws Throwable {

	Object result;
	MethodHandler methodHandler = this.dispatch.get(method);
	// only handle by HardCodedTarget
	if (target instanceof Target.HardCodedTarget) {
		Target.HardCodedTarget hardCodedTarget = (Target.HardCodedTarget) target;
		MethodMetadata methodMetadata = SentinelContractHolder.METADATA_MAP
				.get(hardCodedTarget.type().getName()
						+ Feign.configKey(hardCodedTarget.type(), method));
		// resource default is HttpMethod:protocol://url
		if (methodMetadata == null) {
			result = methodHandler.invoke(args);
		} else {
			String resourceName = methodMetadata.template().method().toUpperCase()
					+ ":" + hardCodedTarget.url() + methodMetadata.template().path();
			Entry entry = null;
			try {
				ContextUtil.enter(resourceName);
				entry = SphU.entry(resourceName, EntryType.OUT, 1, args);
				result = methodHandler.invoke(args);
			} catch (Throwable ex) {
				// fallback handle
				if (!BlockException.isBlockException(ex)) {
					Tracer.trace(ex);
				}
				if (fallbackFactory != null) {
					try {
						Object fallbackResult = fallbackMethodMap.get(method)
								.invoke(fallbackFactory.create(ex), args);
						return fallbackResult;
					} catch (IllegalAccessException e) {
						throw new AssertionError(e);
					} catch (InvocationTargetException e) {
						throw new AssertionError(e.getCause());
					}
				} else {
					throw ex;
				}
			} finally {
				if (entry != null) {
					entry.exit(1, args);
				}
				ContextUtil.exit();
			}
		}
	} else {
		result = methodHandler.invoke(args);
	}

	return result;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值