使用过FeignClient的同学可能都知道,FeignClient在使用的过程中会生成一个代理类,所有操作都是由代理类去完成,这个的确是这样的,但是当有人问这个代理类是如何生成的?这个代理类做了哪些事情呢?不熟悉代理生成过程的我们可能就会不知如何回答,所以本节的我们使命就是分析FeignClient代理生成过程!
FeignClientFactoryBean
Spring Cloud Feign 分析(一)之FeignClient注册过程中讲解过FeignClientsRegistrar#registerFeignClients这个方法中return factoryBean.getObject();会返回一个代理对象,但是并没有深入讲解,特此放到本节进行统一讲解!
public class FeignClientFactoryBean implements FactoryBean
经过我们不懈努力,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 target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget 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 targetWithFallbackFactory(String feignClientName, FeignContext context,
Target.HardCodedTarget 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 targetWithFallback(String feignClientName, FeignContext context,
Target.HardCodedTarget target, HystrixFeign.Builder builder,
Class> fallback) {
//获取降级实例
T fallbackInstance = getFromContext("fallback", feignClientName, context,
fallback, target.type());
//返回具有fallback的代理实例
return builder.target(target, fallbackInstance);
}
//返回指定类型的实例
private T getFromContext(String fallbackMechanism, String feignClientName,
FeignContext context, Class> beanType, Class targetType) {
......
return (T) fallbackInstance;
}
//根据@FeignClient注解的name、value属性值获取对应beanType实例
private T getOptional(String feignClientName, FeignContext context,
Class beanType) {
return context.getInstance(feignClientName, beanType);
}
}
通过上文中FeignClientFactoryBean的步骤中可知,在HystrixTargeter#target这个方法中最后一段return feign.target(target);经过的步骤如下:
- 调用Feign#Builder#target(Target
target) - 调用HystrixFeign#build()
- 调用HystrixFeign#build(final FallbackFactory> nullableFallbackFactory)
- 调用Feign#build()
- 调用ReflectiveFeign#newInstance(Target
target) - 返回代理对象proxy
HystrixTargeter汇总的步骤大约是6个步骤,但是这6个步骤因为存在来回调用,所以在下文里会重点分析每个步骤具体做了哪些事情,这样才有利于我们清楚生成代理对象的整个过程!
Feign#Builder
public abstract class Feign {
......
//会调用到ReflectiveFeign#newInstance(Target target)
public abstract T newInstance(Target target);
//返回代理对象
public static class Builder {
public T target(Target 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 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
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 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 newInstance(Target target) {
//ParseHandlerByName解析接口得到方法名称和对应的MethodHandler
Map nameToHandler = targetToHandlersByName.apply(target);
//方法和对应的MethodHandler
Map methodToHandler = new LinkedHashMap();
//默认方法集合
List defaultMethodHandlers = new LinkedList();
//反射获取@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的调用过程,因为知道整个调用过程对我们排查问题非常有用!