前言
之前已经阅读过Feign和Hystrix的源码了,这章进行spring-cloud-openfeign-core与Hystrix集成的源码分析。
之前的文章:
-
Feign
- Feign源码阅读(一)FeignContext命名容器工厂:juejin.cn/post/687847…
- Feign源码阅读(二)FeignClient动态代理 :juejin.cn/post/687848…
- Feign源码阅读(三)FeignClient定制化配置 :juejin.cn/post/687856…
- Feign源码阅读(四)Feign动态代理执行流程解析:juejin.cn/post/687886…
- Feign源码阅读(五)常见问题解析 :juejin.cn/post/687890…
-
Hystrix
- Hystrix源码阅读(一)HystrixCommand的四种执行方式 :juejin.cn/post/688046…
- Hystrix源码阅读(二)缓存、熔断、资源隔离、降级 :juejin.cn/post/688149…
一、FeignClientFactoryBean创建JDK动态代理
FeignClientFactoryBean#getObject创建Bean实例
@Override
public Object getObject() throws Exception {
return getTarget();
}
/**
* T就是目标接口的类型
*/
<T> T getTarget() {
// 获取FeignContext子容器工厂
FeignContext context = this.applicationContext.getBean(FeignContext.class);
// 获取HystrixFeign.Builder
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
this.url += cleanPath();
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
// 省略写死url的逻辑...
}
// 获取Targeter,执行target方法获取动态代理
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
// org.springframework.cloud.openfeign.HystrixTargeter
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?");
}
HystrixTargeter.target创建动态代理
class HystrixTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
// 如果没配置feign.hystrix.enabled=true,默认的Builder就是Feign.Builder
// 不会走Hystrix的逻辑
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
// 默认实现是feign.hystrix.SetterFactory.Default
SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
// 优先获取fallback对应的Class构造代理
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(name, context, target, builder, fallback);
}
// 其次获取fallbackFactory对应的Class构造代理
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder,
fallbackFactory);
}
// 如果fallback和fallbackFactory都没获取到,则不启用Hystrix的降级逻辑
return feign.target(target);
}
}
targetWithFallback
降级逻辑由@FeignClient注解的fallback指定的类提供。
private <T> T targetWithFallback(String feignClientName, FeignContext context,
Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
Class<?> fallback) {
// feignClientName和fallback从子容器获取对应的Bean
T fallbackInstance = getFromContext("fallback", feignClientName, context,
fallback, target.type());
// 调用HystrixFeign.Builder的target方法
return builder.target(target, fallbackInstance);
}
targetWithFallbackFactory
降级逻辑由@FeignClient注解的fallbackFactory指定的类提供。
private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
Target.HardCodedTarget<T> target, HystrixFeign.Builder builder,
Class<?> fallbackFactoryClass) {
// 通过feignClientName和fallbackFactoryClass获取子容器中的FallbackFactory实现类
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext(
"fallbackFactory", feignClientName, context, fallbackFactoryClass,
FallbackFactory.class);
// 调用HystrixFeign.Builder的target方法
return builder.target(target, fallbackFactory);
}
HystrixFeign.Builder构造ReflectiveFeign
- 通过fallback构造ReflectiveFeign
public <T> T target(Target<T> target, T fallback) {
// 把fallback放入FallbackFactory.Default
// FallbackFactory.Default的create方法会直接返回这个fallback实例
ReflectiveFeign feign = build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null);
return feign.newInstance(target);
}
- 通过fallbackFactory构造ReflectiveFeign
public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
ReflectiveFeign feign = build(fallbackFactory);
return feign.newInstance(target);
}
- 构造无降级ReflectiveFeign
@Override
public Feign build() {
return build(null);
}
HystrixFeign.Builder#build(feign.hystrix.FallbackFactory<?>)
统一构造ReflectiveFeign的入口
Feign build(final FallbackFactory<?> nullableFallbackFactory) {
// 设置创建JDKInvocationHandler的工厂
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@Override
public InvocationHandler create(Target target,
Map<Method, MethodHandler> dispatch) {
// 创建HystrixInvocationHandler
return new HystrixInvocationHandler(target, dispatch, setterFactory,
nullableFallbackFactory);
}
});
// 代理SpringMvcContract,对方法元数据解析做一些Hystrix相关的定制改造
super.contract(new HystrixDelegatingContract(contract));
// 构造ReflectiveFeign
return super.build();
}
ReflectiveFeign#newInstance()方法创建JDK动态代理,省略无关方法
@Override
public <T> T newInstance(Target<T> target) {
// 获取方法名对应的处理类的映射关系
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
// 创建HystrixInvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 创建JDK动态代理
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
return proxy;
}
二、HystrixInvocationHandler执行HystrixCommand
成员变量及构造方法
final class HystrixInvocationHandler implements InvocationHandler {
// HardCodedTarget实例
// 封装原始FeignClient接口Class、服务名(trade-service)、url(http://trade-service)
private final Target<?> target;
// 目标方法 - 实际处理Handler
private final Map<Method, MethodHandler> dispatch;
// 降级工厂
private final FallbackFactory<?> fallbackFactory; // Nullable
// 目标方法 - 目标方法 setAccessible(true)的
private final Map<Method, Method> fallbackMethodMap;
// 目标方法 - com.netflix.hystrix.HystrixCommand.Setter
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;
// 构造目标方法 - 目标方法映射,主要是为了防止invoke方法多次调用setAccessible(true)
this.fallbackMethodMap = toFallbackMethod(dispatch);
// 构造目标方法 - com.netflix.hystrix.HystrixCommand.Setter
this.setterMethodMap = toSetters(setterFactory, target, dispatch.keySet());
}
static Map<Method, Method> toFallbackMethod(Map<Method, MethodHandler> dispatch) {
Map<Method, Method> result = new LinkedHashMap<Method, Method>();
for (Method method : dispatch.keySet()) {
method.setAccessible(true);
result.put(method, method);
}
return result;
}
static Map<Method, Setter> toSetters(SetterFactory setterFactory,
Target<?> target,
Set<Method> methods) {
Map<Method, Setter> result = new LinkedHashMap<Method, Setter>();
for (Method method : methods) {
method.setAccessible(true);
// 调用SetterFactory的create方法创建Hystrix的Setter
result.put(method, setterFactory.create(target, method));
}
return result;
}
}
SetterFactory
SetterFactory
的默认实现feign.hystrix.SetterFactory.Default
。HystrixCommandGroupKey取HardCodedTarget实例的name属性,也就是服务名。HystrixCommandKey取的是StockClient#getStock(Long)
类名和方法签名的拼接。所以默认FeignHystrix资源隔离的线程池维度是HystrixCommandGroupKey,一个服务名一个线程池。
final class Default implements SetterFactory {
@Override
public HystrixCommand.Setter create(Target<?> target, Method method) {
String groupKey = target.name();
String commandKey = Feign.configKey(target.type(), method);
return HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
}
}
HystrixInvocationHandler#invoke
feign.hystrix.HystrixInvocationHandler#invoke
构造HystrixCommand,并根据方法返回参数类型,决定是否同步执行execute
方法。
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;
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
// 如果是Object提供的方法,和ReflectiveFeign.FeignInvocationHandler的处理方式一致,省略
// ...
// 创建HystrixCommand
HystrixCommand<Object> hystrixCommand =
new HystrixCommand<Object>(setterMethodMap.get(method)) {
@Override
protected Object run() throws Exception {
// 获取MethodHandler执行方法 和ReflectiveFeign.FeignInvocationHandler的处理方式一致
return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
}
@Override
protected Object getFallback() {
// 如果fallbackFactory为空
// 抛出throw new UnsupportedOperationException("No fallback available.")
if (fallbackFactory == null) {
return super.getFallback();
}
// getExecutionException获取HystrixCommand执行过程中的异常
// 调用自己定义的fallbackFactory的create方法创建fallback
Object fallback = fallbackFactory.create(getExecutionException());
// 反射调用fallback的对应方法
Object result = fallbackMethodMap.get(method).invoke(fallback, args);
// 解析方法的返回类型
if (isReturnsHystrixCommand(method)) {
// 如果是HystrixCommand,那么直接执行execute方法同步返回
return ((HystrixCommand) result).execute();
} else if (...) {
// 省略其他类型判断,做特殊返回
// 比如Single、CompletableFuture等等,都是直接同步返回
return ...;
} else {
// 普通类型
return result;
}
}
};
// 解析方法返回类型,确定HystrixCommand如何返回
if (Util.isDefault(method)) {
// 如果是默认方法直接同步执行
return hystrixCommand.execute();
} else if (isReturnsHystrixCommand(method)) {
// 如果是HystrixCommand,直接返回HystrixCommand实例,不执行
return hystrixCommand;
} else if (isReturnXXX(...)) {
// ...省略其他返回类型的特殊处理
}
// 正常返回类型,同步执行HystrixCommand的execute方法
return hystrixCommand.execute();
}
}
三、问题
疑问一
看完HystrixInvocationHandler#invoke
方法,注意到对于方法返回类型做了特殊处理,什么场景会使用到这些特殊处理呢。
比如我们可以这样使用FeignClient,虽然都是调用http://trade-service/getStockByMpId/{mpId}
但是两个方法的返回值类型不一样:
@FeignClient(primary = false, name = "trade-service", fallbackFactory = StockServiceFallBackFactory.class, configuration = StockServiceFallBackFactory.class)
public interface StockClient {
@RequestMapping(value = "/getStockByMpId/{mpId}", method = RequestMethod.GET)
ApiResponse<Stock> getStock(@PathVariable("mpId") Long mpId);
// 特殊的返回值类型,如HystrixCommand
@RequestMapping(value = "/getStockByMpId/{mpId}", method = RequestMethod.GET)
HystrixCommand<ApiResponse<Stock>> getStock2(@PathVariable("mpId") Long mpId);
}
public class StockServiceFallBackFactory implements FallbackFactory<StockClient> {
@Override
public StockClient create(Throwable throwable) {
return new StockClient() {
@Override
public ApiResponse<Stock> getStock(Long mpId) {
return ApiResponse.fail("商品id:" + mpId + ", error = "+ throwable.getMessage());
}
@Override
public HystrixCommand<ApiResponse<Stock>> getStock2(Long mpId) {
HystrixCommand.Setter setter = HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("fallback"));
return new HystrixCommand<ApiResponse<Stock>>(setter) {
@Override
protected ApiResponse<Stock> run() throws Exception {
// 可能是又一次网络通信,比如请求某个降级服务
Stock stock = new Stock();
stock.setMpId(mpId);
stock.setStockNum(0);
return ApiResponse.success(stock);
}
};
}
};
}
}
public class Test {
@Autowired
private StockClient stockClient;
@Test
public void test01() {
// 同步执行
System.out.println(stockClient.getStock(1L));
}
@Test
public void test02() {
// 创建HystrixCommand但是并没有执行
HystrixCommand<ApiResponse<Stock>> command = stockClient.getStock2(3L);
System.out.println(command.isSuccessfulExecution());
// 先用trade-service线程池执行远程调用
// 降级使用fallback线程池执行某个降级服务的远程调用
System.out.println(command.execute());
}
}
为什么要这样做呢?因为上一章讲过fallback尽量避免阻塞操作,比如网络通信。如果因为业务需要,非得在fallback里做远程调用。那么可以返回HystrixCommand,这样fallback就可以换一个HystrixCommandGroupKey在另外的线程池,并且具有隔离的资源和独立的熔断指标统计。
疑问二
服务提供方返回的是ApiResponse
,为什么FeignClient的方法返回类型是HystrixCommand
,远程调用以后的反序列化不会失败呢?
原因是HystrixDelegatingContract
的parseAndValidateMetadata
篡改了MethodMetadata
里的returnType
属性,Decoder
反序列化是参照returnType
属性执行的。
public final class HystrixDelegatingContract implements Contract {
private final Contract delegate;
public HystrixDelegatingContract(Contract delegate) {
this.delegate = delegate;
}
@Override
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
// 先用SpringMvcContract解析方法元信息
List<MethodMetadata> metadatas = this.delegate.parseAndValidateMetadata(targetType);
// 然后获取参数化类型
for (MethodMetadata metadata : metadatas) {
Type type = metadata.returnType();
// 如果是HystrixCommand<T>,设置返回值类型是T
if (type instanceof ParameterizedType
&& ((ParameterizedType) type).getRawType().equals(HystrixCommand.class)) {
Type actualType = resolveLastTypeParameter(type, HystrixCommand.class);
metadata.returnType(actualType);
} else if (...) {
// ... 省略其他返回值类型判断
}
}
return metadatas;
}
}
总结
spring-cloud-openfeign-core与Hystrix集成是在InvocationHandler里创建了HystrixCommand,支持降级,但是不支持缓存(创建的HystrixCommand没有重写getCacheKey方法)。
FeignClient可以返回特殊类型,比如HystrixCommand类型,这样可以在fallback里进行阻塞操作,比如远程调用。