Spring如何識别@FeignClient
從@EnableFeignClients 出發,尋找Spring如何識别FeignClient
從源碼中檢視到@Import(FeignClientsRegistrar.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
// 省略内部代碼
}
檢視FeignClientsRegistrar 的類圖如下,
ResourceLoaderAware 注入 ResourceLoader
EnvironmentAware 注入 Environment
ImportBeanDefinitionRegistrar: 注冊額外的beanDefinition
ImportBeanDefinitionRegistrar# registerBeanDefinitions ,FeignClientsRegistrar 的實作如下:
@Override
public void registerBeanDefinitions(
AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 處理@EnableFeignClients上的defaultConfiguration配置
registerDefaultConfiguration(metadata, registry);
// 處理@FeignClient注解
registerFeignClients(metadata, registry);
}
查閱registerFeignClients 部分的代碼,大緻邏輯為找到@FeignClient标注的接口,注冊到Spring,那注冊到Spring的Bean是什麼呢??
我們一起來檢視下registerFeignClient 方法, FeignClientFactoryBean 就是我們要找的主角了。
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 的代碼如下:
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()
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 邏輯
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的大緻邏輯就分析完了。