Spring如何识别@FeignClient
从@EnableFeignClients 出发,寻找Spring如何识别FeignClient
从源码中查看到@Import(FeignClientsRegistrar.class)
代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
// 省略内部代码
}
查看FeignClientsRegistrar 的类图如下,
ResourceLoaderAware 注入 ResourceLoader
EnvironmentAware 注入 Environment
ImportBeanDefinitionRegistrar: 注册额外的beanDefinition
ImportBeanDefinitionRegistrar# registerBeanDefinitions ,FeignClientsRegistrar 的实现如下:
代码语言:javascript复制 @Override
public void registerBeanDefinitions(
AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 处理@EnableFeignClients上的defaultConfiguration配置
registerDefaultConfiguration(metadata, registry);
// 处理@FeignClient注解
registerFeignClients(metadata, registry);
}
查阅registerFeignClients 部分的代码,大致逻辑为找到@FeignClient标注的接口,注册到Spring,那注册到Spring的Bean是什么呢??
我们一起来查看下registerFeignClient 方法, FeignClientFactoryBean 就是我们要找的主角了。
代码语言:javascript复制private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
Class clazz = ClassUtils.resolveClassName(className, null);
ConfigurableBeanFactory beanFactory = registry instanceof ConfigurableBeanFactory
? (ConfigurableBeanFactory) registry : null;
String contextId = getContextId(beanFactory, attributes);
String name = getName(attributes);
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
// 省略大部分代码
}
至此我们可以得出如下结论:
FeignClientsRegistrar 实现了ImportBeanDefinitionRegistrar# registerBeanDefinitions 方法,内部扫描@FeignClient注解的接口,转化为 FeignClientFactoryBean 注入Spring。
FeignClientFactoryBean 做了什么?
这里我们关注FactoryBean#getObject,(其他扩展点从源码中查看并不重要)
getObject 委托给了getTarget(): 内部代码,有2点关注,
一个就是说明了负载均衡的client是FeignBlockingLoadBalancerClient,
二,最终委托给了,org.springframework.cloud.openfeign.Targeter.target
Targeter 的默认实现是DefaultTargeter ,内部调用了Feign#target
Feign#target 的代码如下:
代码语言:javascript复制 public <T> T target(Target<T> target) {
return build().newInstance(target);
}
public Feign build() {
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 invocationHandlerFactory =
Capability.enrich(this.invocationHandlerFactory, capabilities);
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
}
ReflectiveFeign 是其内部实现 。
这段代码的大致逻辑如下:
总结下就是:
FeignClientFactoryBean#getObject 第一步 Feign.Builder#build() 创建ReflectiveFeign
之后我们来看ReflectiveFeign# newInstance()
代码语言:javascript复制 public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else if (Util.isDefault(method)) {
DefaultMethodHandler handler = new DefaultMethodHandler(method);
defaultMethodHandlers.add(handler);
methodToHandler.put(method, handler);
} else {
methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
}
}
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
new Class<?>[] {target.type()}, handler);
for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
defaultMethodHandler.bindTo(proxy);
}
return proxy;
}
内部是JDK的动态代理,核心逻辑在ReflectiveFeign.FeignInvocationHandler
FeignClientFactoryBean#getObject 第二步 依托ReflectiveFeign #newInstance ,使用JDK动态代理实现,对接口的增强,ReflectiveFeign.FeignInvocationHandler 有调用的逻辑
ReflectiveFeign.FeignInvocationHandler 逻辑
代码语言:javascript复制static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("equals".equals(method.getName())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".equals(method.getName())) {
return hashCode();
} else if ("toString".equals(method.getName())) {
return toString();
}
return dispatch.get(method).invoke(args);
}
策略模式,具体的执行委托给了MethodHandler ,MethodHandler的一个实现是SynchronousMethodHandler
代码很长,这里跳过,直接给出最终的 逻辑调用链条
FeignInvocationHandler 策略模式,委托给MethodHandler , SynchronousMethodHandler 底层依托于LoadBalanceClient 实现负载均衡 LoadBalanceClient 的实现是FeignBlockingLoadBalanceClient LoadBalanceClient#choose 底层依托于ReactiveLoadBalancer#choose ReactiveLoadBalancer 的一个实现是NacosLoaderBalance#choose
至此,FeignClient的大致逻辑就分析完了。