首页 > 编程 > Java > 正文

spring cloud openfeign 源码实例解析

2019-11-26 08:28:58
字体:
来源:转载
供稿:网友

一、读取注解信息

入口

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication@EnableFeignClientspublic class CjsPriceServiceApplication {  public static void main(String[] args) {    SpringApplication.run(CjsPriceServiceApplication.class, args);  }}

spring boot 项目启动后会自动扫描application上面的注解,@EnableFeignClients的注解如下

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(FeignClientsRegistrar.class)public @interface EnableFeignClients {。。。。}

在注解中导入了 FeignClientsRegistrar类,用来像spring注册,EnableFeignClients和FeignClient上面开发人员添加的注解信息

@Override  public void registerBeanDefinitions(AnnotationMetadata metadata,      BeanDefinitionRegistry registry) {    registerDefaultConfiguration(metadata, registry);    registerFeignClients(metadata, registry);  }

二、当项目启动,读取@Autowired时会调用,实现了FactoryBean接口的FeignClientFactoryBean.getObject()方法

   @Override   public Object getObject() throws Exception {     return getTarget();   }
<T> T getTarget() {    FeignContext context = this.applicationContext.getBean(FeignContext.class);    Feign.Builder builder = feign(context);    if (!StringUtils.hasText(this.url)) {      if (!this.name.startsWith("http")) {        this.url = "http://" + this.name;      }      else {        this.url = this.name;      }      this.url += cleanPath();      return (T) loadBalance(builder, context,          new HardCodedTarget<>(this.type, this.name, this.url));    }    if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {      this.url = "http://" + this.url;    }    String url = this.url + cleanPath();    Client client = getOptional(context, Client.class);    if (client != null) {      if (client instanceof LoadBalancerFeignClient) {        // not load balancing because we have a url,        // but ribbon is on the classpath, so unwrap        client = ((LoadBalancerFeignClient) client).getDelegate();      }      builder.client(client);    }    Targeter targeter = get(context, Targeter.class);    return (T) targeter.target(this, builder, context,        new HardCodedTarget<>(this.type, this.name, url));  }

可以看到 getTarget()有两种返回结果的情况,其原理都一样后来调用了 targeter.target()方法

package org.springframework.cloud.openfeign;import feign.Feign;import feign.Target;/** * @author Spencer Gibb */interface Targeter {  <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,      FeignContext context, Target.HardCodedTarget<T> target);}

默认实现类

package org.springframework.cloud.openfeign;import feign.Feign;import feign.Target;/** * @author Spencer Gibb */class DefaultTargeter implements Targeter {  @Override  public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,      FeignContext context, Target.HardCodedTarget<T> target) {    return feign.target(target);  }}

然后再看 feign.target(target);方法

public <T> T target(Target<T> target) {   return build().newInstance(target);  }  public Feign build() {   SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =     new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,       logLevel, decode404, closeAfterDecode, propagationPolicy);   ParseHandlersByName handlersByName =     new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,       errorDecoder, synchronousMethodHandlerFactory);   return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);  } }

build()方法返回了创建代理类的对象,然后调用了创建代理的 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; }

最后,当我们项目中使用 @Autowired注入时,就回调用工厂类 FeignClientFactoryBean方法的 getObject()方法 返回我们的代理对象

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表