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