Spring Cloud Feign 分析(五)之FeignCl
使用过FeignClient的同学可能都知道,FeignClient在使用的过程中会生成一个代理类,所有操作都是由代理类去完成,这个的确是这样的,但是当有人问这个代理类是如何生成的?这个代理类做了哪些事情呢?不熟悉代理生成过程的我们可能就会不知如何回答,所以本节的我们使命就是分析FeignClient代理生成过程!
FeignClientFactoryBean
Spring Cloud Feign 分析(一)之FeignClient注册过程中讲解过FeignClientsRegistrar#registerFeignClients这个方法中return factoryBean.getObject();会返回一个代理对象,但是并没有深入讲解,特此放到本节进行统一讲解!
public class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
ApplicationContextAware, BeanFactoryAware {
......
//创建HystrixFeign.builder
protected Feign.Builder feign(FeignContext context) {
//创建DefaultFeignLoggerFactory
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
//默认返回Slf4jLogger
Logger logger = loggerFactory.create(type);
//获取HystrixFeign.Builder
Feign.Builder builder = get(context, Feign.Builder.class)
//默认Slf4jLogger
.logger(logger)
//默认SpringEncoder
.encoder(get(context, Encoder.class))
//默认SpringDecoder
.decoder(get(context, Decoder.class))
//默认SpringMvcContract
.contract(get(context, Contract.class));
//设置Feign.Builder 的其他配置,如ErrorDecoder、Retryer等配置
configureFeign(context, builder);
//扩展给外部使用者,外部使用者可以给Feign.Builder设置其他参数
applyBuildCustomizers(context, builder);
//返回Feign.Builder => HystrixFeign.Builder
return builder;
}
//获取代理对象
@Override
public Object getObject() {
return getTarget();
}
//代理对象实现过程,根据url参数区分使用哪一种策略
<T> T getTarget() {
//获取FeignContext工厂类
FeignContext context = beanFactory != null
? beanFactory.getBean(FeignContext.class)
: applicationContext.getBean(FeignContext.class);
//获取HystrixFeign.builder()
Feign.Builder builder = feign(context);
//如果@FeignClient中为配置url,则使用如下方式,负载均衡方式
if (!StringUtils.hasText(url)) {
if (!name.startsWith("http")) {
url = "http://" + name;
}
else {
url = name;
}
url += cleanPath();
//设置client为LoadBalancerFeignClient,具备负载均衡
//返回HystrixTargeter.target中返回的代理类
return (T) loadBalance(builder, context,
new HardCodedTarget<>(type, name, url));
}
//@FeignClient中配置的url,使用如下方式,以下方式均为不使用负载均衡的方式
if (StringUtils.hasText(url) && !url.startsWith("http")) {
url = "http://" + url;
}
String url = this.url + cleanPath();
Client client = getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
client = ((LoadBalancerFeignClient) client).getDelegate();
}
if (client instanceof FeignBlockingLoadBalancerClient) {
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
//返回的client为Client.Default,不具备负载均衡作用
builder.client(client);
}
//返回HystrixTargeter.target中返回的代理类
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context,
new HardCodedTarget<>(type, name, url));
}
}
经过我们不懈努力,FeignClientFactoryBean这个代理工厂类中代码片段已经标上了注释信息,为了便于我们更好的理解,我们汇总一下执行步骤:
- 获取FeignContext这个Feign工厂类上下文,用于从中获取所需的Bean
- 从FeignContext上下文中获取HystrixFeign.builder
- 设置HystrixFeign.builder的logger(Slf4jLogger)、encoder(默认SpringEncoder)、decoder(默认SpringDecoder)、contract(默认SpringMvcContract),如果有自定义实现则使用,否则使用默认值
- 设置Feign.Builder 的其他配置,如ErrorDecoder、Retryer等配置
- 将HystrixFeign.builder外抛给外部用于扩展,使用者可以设置相关参数
- 根据@FeignClient中配置是否配置了url参数,为Feign.Builder设置client参数,client分为负载均衡方式与非负载均衡方式
- 返回HystrixTargeter.target中返回的代理类
HystrixTargeter
class HystrixTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
//是否为Feign.Builder 类型,若不是则直接创建代理对象并执行
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
//转换为HystrixFeign.Builder类型
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
//获取上下文id,其实就是获取的@FeignClient注解的name、value属性值
String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
: factory.getContextId();
//获取SetterFactory,主要是HystrixCommand的groupKey、commandKey参数,默认setterFactory为空
SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
//setterFactory不为空就设置
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
//获取降级方法,默认为void初始状态
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
//如果有设置了fallback,则使用
return targetWithFallback(name, context, target, builder, fallback);
}
//获取降级工厂类FallbackFactory,默认为void初始状态
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder,
fallbackFactory);
}
//调用HystrixFeign#build()
return feign.target(target);
}
//具有FallbackFactory的目标执行类
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);
//返回具有FallbackFactory的代理实例
return builder.target(target, fallbackFactory);
}
//具有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());
//返回具有fallback的代理实例
return builder.target(target, fallbackInstance);
}
//返回指定类型的实例
private <T> T getFromContext(String fallbackMechanism, String feignClientName,
FeignContext context, Class<?> beanType, Class<T> targetType) {
......
return (T) fallbackInstance;
}
//根据@FeignClient注解的name、value属性值获取对应beanType实例
private <T> T getOptional(String feignClientName, FeignContext context,
Class<T> beanType) {
return context.getInstance(feignClientName, beanType);
}
}
通过上文中FeignClientFactoryBean的步骤中可知,在HystrixTargeter#target这个方法中最后一段return feign.target(target);经过的步骤如下:
- 调用Feign#Builder#target(Target<T> target)
- 调用HystrixFeign#build()
- 调用HystrixFeign#build(final FallbackFactory<?> nullableFallbackFactory)
- 调用Feign#build()
- 调用ReflectiveFeign#newInstance(Target<T> target)
- 返回代理对象proxy
HystrixTargeter汇总的步骤大约是6个步骤,但是这6个步骤因为存在来回调用,所以在下文里会重点分析每个步骤具体做了哪些事情,这样才有利于我们清楚生成代理对象的整个过程!
Feign#Builder
public abstract class Feign {
......
//会调用到ReflectiveFeign#newInstance(Target<T> target)
public abstract <T> T newInstance(Target<T> target);
//返回代理对象
public static class Builder {
public <T> T target(Target<T> target) {
//build()这个方法会调用到HystrixFeign#build()
return build().newInstance(target);
}
//基础build,Capability可以理解为增强功能,通过增强,可以对Client这些配置进行额外操作,默认不会增强,返回原始值
public Feign build() {
//默认返回原始Client,以下都是未增强的,都是原始值
Client client = Capability.enrich(this.client, capabilities);
Retryer retryer = Capability.enrich(this.retryer, capabilities);
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Encoder encoder = Capability.enrich(this.encoder, capabilities);
Decoder decoder = Capability.enrich(this.decoder, capabilities);
//InvocationHandlerFactory工厂类,负责创建InvocationHandler代理类的执行方法
InvocationHandlerFactory invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
//负责创建SynchronousMethodHandler方法执行Handler的工厂类
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
//用于解析接口得到方法名称和对应的MethodHandler
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
//返回代理实例
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
......
}
在调用target(Target<T> target)方法之后,因为HystrixFeign#Builder继承Feign.Builder,所以默认会执行下文中的HystrixFeign#build方法,然后HystrixFeign#build()方法中会设置Hystrix相关的配置,在Feign#build()这个方法中会通过增强Capability接口进行获取相关的配置,可以对Client这些配置进行额外操作,默认不会增强,返回原始值,最终将相关的参数设置给ReflectiveFeign并返回最终的代理对象!
HystrixFeign#build
public final class HystrixFeign {
public static final class Builder extends Feign.Builder {
......
@Override
public Feign build() {
return build(null);
}
//配置组件具备hystrix功能
Feign build(final FallbackFactory<?> nullableFallbackFactory) {
//设置代理对象的InvocationHandler,会将执行的方法HystrixCommand.execute(),这样就具备了Hystrix的熔断能力
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@Override
public InvocationHandler create(Target target,
Map<Method, MethodHandler> dispatch) {
//HystrixInvocationHandler实现了InvocationHandler,会在ReflectiveFeign#newInstance中设置到代理类中
return new HystrixInvocationHandler(target, dispatch, setterFactory,
nullableFallbackFactory);
}
});
//将我们原本的contract协议具备Hystrix能力
super.contract(new HystrixDelegatingContract(contract));
//调用父类Feign#Builder#build()
return super.build();
}
......
}
}
HystrixFeign#build这个方法就比较直观,就是配置组件具备hystrix功能,通过创建具备Hystrix熔断功能的InvocationHandler拦截器,然后内部通过HystrixCommand.execute()来触发请求,contract也包装给HystrixDelegatingContract让其具备Hystrix处理能力!
ReflectiveFeign#newInstance
public class ReflectiveFeign extends Feign {
......
@Override
public <T> T newInstance(Target<T> target) {
//ParseHandlerByName解析接口得到方法名称和对应的MethodHandler
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
//方法和对应的MethodHandler
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
//默认方法集合
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
//反射获取@FeignClient接口声明方法
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
//Default methods are public non-abstract, non-synthetic, and non-static instance methods
//正常情况下@FeignClient接口不会走这里
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
//@FeignClient接口方法放入到methodToHandler中
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
//通过invocationHandlerFactory创建HystrixInvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
//JDK动态代理创建代理对象并设置代理类的InvocationHandler,这样就可以通过Hystrix发起请求
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
//将接口的默认方法绑定到生成的代理对象
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
......
}
ReflectiveFeign#newInstance这个方法中,我们可以看到其实就是在解析target这个对象,因为这个target是由@FeignClient注解包装而来的,所以大致步骤为:
- 通过ParseHandlerByName解析接口得到方法名称和对应的MethodHandler,其中Key => Class#Function(String,String,String),Class即为定义了@FeignClient注解的接口类名,Function则为该接口中的方法名
- 反射获取@FeignClient接口声明方法,将其加入methodToHandler这个方法和对应的MethodHandler
- 通过invocationHandlerFactory创建HystrixInvocationHandler
- JDK动态代理创建代理对象并设置代理类的InvocationHandler,这样就可以通过Hystrix发起请求
- 将接口的默认方法绑定到生成的代理对象 => 正常情况不会有
- 返回代理对象proxy
生成代理对象这个过程非常的复杂,我也只是总结了自己认为比较重要的部分,如果有兴趣可以在看看ParseHandlerByName这个解析接口的过程,相信对我们的代码设计能力有所帮助,后续的章节会继续讲解@FeignClient的调用过程,因为知道整个调用过程对我们排查问题非常有用!