Open Feign整個核心的調用過程大緻如下:
下面根據源碼詳細分析:
- @EnableFeignClients引入FeignClientsRegistrar類實作了ImportBeanDefinitionRegistrar接口用過registerBeanDefinitions方法向spring容器中注入FeignClientSpecification類(FeignClient需要的重試政策,逾時政策,日志等配置,如果某個服務沒有設定,則讀取預設的配置)
// 通過開啟feign注解引入FeignClientsRegistrar類
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
//.....
}
FeignClientsRegistrar實作了ImportBeanDefinitionRegistrar類,重寫registerBeanDefinitions方法可以自定義bean在spring中的注冊:
//自定義注冊bean到spring容器
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
//...
//自定義實作注冊bean
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
this.registerDefaultConfiguration(metadata, registry);
this.registerFeignClients(metadata, registry);
}
//掃描包所有加了@FeignClient的接口類,并将其注冊到spring容器中。
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//...
Iterator var17 = ((Set)basePackages).iterator();
while(var17.hasNext()) {
String basePackage = (String)var17.next();
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
Iterator var21 = candidateComponents.iterator();
while(var21.hasNext()) {
BeanDefinition candidateComponent = (BeanDefinition)var21.next();
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = this.getClientName(attributes);
this.registerClientConfiguration(registry, name, attributes.get("configuration"));
this.registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
}
2.接着上面的registerFeignClient()方法,成feign client bean的包裝類FeignClientFactoryBean,并将@FeignClient注解的屬性注冊到bean中。注冊的FeignClientFactoryBean,是一個包裝了我們需要執行的rpc服務的請求的類、url、服務名稱以及回調方法等。
//生成feign client bean的包裝類FeignClientFactoryBean,并将@FeignClient注解的屬性注冊到bean中。
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
this.validate(attributes);
definition.addPropertyValue("url", this.getUrl(attributes));
definition.addPropertyValue("path", this.getPath(attributes));
String name = this.getName(attributes);
definition.addPropertyValue("name", name);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(2);
String alias = name + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = (Boolean)attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = this.getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
FeignClientFactoryBean類定義:
private Class<?> type;
private String name;
private String url;
private String path;
private boolean decode404;
private ApplicationContext applicationContext;
private Class<?> fallback;
private Class<?> fallbackFactory;
3.FeignClientFactoryBean實作了FactoryBean<Object>接口,在注解使用執行個體對象的時候會從spring容器中擷取,擷取方式就是調用FactoryBean的getObject()方法:
public interface FactoryBean<T> {
@Nullable
T getObject() throws Exception;
@Nullable
Class<?> getObjectType();
default boolean isSingleton() {
return true;
}
//擷取代理對象
public Object getObject() throws Exception {
FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
Builder builder = this.feign(context);
String url;
//FeignClient不存在url的走負載均衡器
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
} else {
url = this.name;
}
url = url + this.cleanPath();
return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, url));
//負載均衡
protected <T> T loadBalance(Builder builder, FeignContext context, HardCodedTarget<T> target) {
Client client = (Client)this.getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targeter targeter = (Targeter)this.get(context, Targeter.class);
return targeter.target(this, builder, context, target);
//擷取目标對象
public <T> T target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget<T> target) {
return feign.target(target);
}
public <T> T target(Target<T> target) {
return this.build().newInstance(target);
}
4.生成預設的處理方法FeignInvocationHandler實作了jdk自帶的動态代理調用接口InvocationHandler,并且為目标類生成代理類;
public <T> T newInstance(Target<T> target) {
//InvocationHandler最終執行的方法
Map<String, MethodHandler> nameToHandler = this.targetToHandlersByName.apply(target);
//...
//建立FeignInvocationHandler包裝類,該類實作了jdk動态代理預設需要實作的接口InvocationHandler,後續通過invoke()方法轉發到nameToHandler中處理
InvocationHandler handler = this.factory.create(target, methodToHandler);
//建立動态代理對象
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
Iterator var12 = defaultMethodHandlers.iterator();
}
//建立FeignInvocationHandler包裝類Target(class、name、url),dispatchd請求分發
public InvocationHandler create(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
return new FeignInvocationHandler(target, dispatch);
}
public InvocationHandler create(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
return new FeignInvocationHandler(target, dispatch);
}
//擷取SynchronousMethodHandler類
public Map<String, MethodHandler> apply(Target key) {
for(Iterator var4 = metadata.iterator(); var4.hasNext(); result.put(md.configKey(), this.factory.create(key, md, (Factory)buildTemplate, this.options, this.decoder, this.errorDecoder))) {
}
//handler重寫後的invoke()方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else {
return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
}
public MethodHandler create(Target<?> target, MethodMetadata md, feign.RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) {
return new SynchronousMethodHandler(target, this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, this.decode404);
}
//Target的屬性
public interface Target<T> {
Class<T> type();
String name();
String url();
}
5.然後走SynchronousMethodHandler的invoke()方法進行真正的rpc調用傳回結果。
//SynchronousMethodHandler調用invoke()方法,開始執行請求
public Object invoke(Object[] argv) throws Throwable {
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
Retryer retryer = this.retryer.clone();
while(true) {
try {
return this.executeAndDecode(template);
} catch (RetryableException var5) {
retryer.continueOrPropagate(var5);
if (this.logLevel != Level.NONE) {
this.logger.logRetry(this.metadata.configKey(), this.logLevel);
}
}
}
}
然後走到client真正開始執行請求的地方:
6.預設的client是LoadBalancerFeignClient,采用負載均衡政策的方式執行我們請求:
下一篇将進一步分析LoadBalancer負載均衡器,講述lb-ribbon涉及的元件和底層工作原理。