SpringCloud OpenFeign源码解析

1.加载并解析@FeignClient注解标记的接口:

在启动类上加@EnableFeignClients,import FeignClientsRegistrar.class;

由于 FeignClientsRegistrar implement ImportBeanDefinitionRegistrar,所以会执行registerBeanDefinitions方法。registerBeanDefinitions方法包含两个方法:

public void registerBeanDefinitions(AnnotationMetadata metadata, 
BeanDefinitionRegistry registry) {
        //将标注@EnableFeignClients的类:com.xxx.Application.java 以
        //default.com.xxx.Application.FeignClientSpecification 为beanName注入到
        //spring容器中。
        //最终,feign相关的对象都以FeignClientSpecification class对象 注入到spring容器中。
		registerDefaultConfiguration(metadata, registry);
        // 重要
		registerFeignClients(metadata, registry);
	}

 registerFeignClients方法主要包含两个方法:

//遍历@EnableFeignClients指定包下面@FeignClient指定的接口,
//为每个feign 生成 FeignClientSpecification 的beanDefinition,
//然后注入spring容器
registerClientConfiguration(registry, name, className, 
attributes.get("configuration"));

// 解析@FeignClient注解的参数,构建FeignClientFactoryBean
registerFeignClient(registry, annotationMetadata, attributes);

构建FeignClientFactoryBean的过程:

放入beanDefinitonMap后:

加载解析@FeignClient结束。

总结:@EnableFeignClients 主要做了两件事

1.将主类和@FeignClient标记的接口转换成FeignClientSpecification对象;

2.解析@FeignClient注解的参数,构建FeignClientFactoryBean对象

2.FeignClientSpecification放入FeignContext中,后续对feign的操作都需要从FeignContext中获取。

(这一步操作和Ribbon一样,Ribbon是将RibbonClientSpecification放入SpringClientFactroy,SpringClientFactory和FeignContext都继承了NamedContextFactory,实现容器隔离,每个ribbon或者feign都有一个独立的容器,互不影响

openfeign-core 包通过SpringBoot的自动装配加载 FeignAutoConfiguration对象

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class,
		FeignEncoderProperties.class })
public class FeignAutoConfiguration {

	private static final Log LOG = LogFactory.getLog(FeignAutoConfiguration.class);

    //引入所有feign对象-FeignClientSpecification
	@Autowired(required = false)
	private List<FeignClientSpecification> configurations = new ArrayList<>();

	public FeignContext feignContext() {
		FeignContext context = new FeignContext();
        //将feign对象放入context中,供FeignClientFactoryBean生成feign的代理对象
	 	context.setConfigurations(this.configurations);
		return context;
	}
	。。。。。。。。。。。。。。。。。。。。。
    。。。。。。。。。。。。。。。。。。。。。
}

这一阶段结束。

总结:将每一个feign对象放入一个独立的FeignContext容器中,供后续操作。

3.FeignClientFactoryBean生成feign代理对象的过程

在业务类中通过@Autowired引入feign定义的接口时,就会创建feign对象,由于beanDefinitionMap中已经存在以接口全路径为key,FeignClientFactoryBean为value的键值对,所以会去创建FeignClientFactoryBean对象。

FeignClientFactoryBean 实现了 FactoryBean 和 InitializingBean:

实现了FactoryBean,通过调用getObject()方法,创建bean对象(懒加载)。

实现了InitializingBean,在Bean初始化时,会调用afterPropertiesSet()方法(在该方法中调用getObject方法,实现提前加载)。

getObject 过程

调用getTarget方法:

在有负载均衡时,调用loadBalance方法:

protected <T> T loadBalance(Feign.Builder builder, FeignClientFactory context, HardCodedTarget<T> target) {
    //获取所有 implement Client 接口的 http工具类
    //(拦截feign打印日志 可以通过 implement Client 来实现)
		Client client = getOptional(context, Client.class);
		if (client != null) {
           //给feign设置 http工具类
			builder.client(client);
            //使用默认的Targeter还是HystrixTargeter是通过
            //FeignAutoConfiguration配置的
			Targeter targeter = get(context, Targeter.class);
            //创建feign代理对象
			return targeter.target(this, builder, context, target);
		}

==============================================================
//获取一个LoadBalancerFeignClient对象(拦截feign日志,自定义Client时,
//需要最终组装LoadBalancerFeignClient对象,才能拦截到)
protected <T> T getOptional(FeignClientFactory context, Class<T> type) {
		return context.getInstance(contextId, type);
	}

==============================================================
LoadBalancerFeignClient implement Client,调用execute方法,
会去调用delegate(也是个Client,自定义Client时,将已经有的Client
通过delegate赋值给自定义的Client,就能调用自定义的Client了)
targeter.target(this, builder, context, target); 创建feign代理对象targeter看HystrixTargeter对象:
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
			FeignContext context, Target.HardCodedTarget<T> target) {
        //非HystrixFeign
		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
			return feign.target(target);
		}
		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
		String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
				: factory.getContextId();
		SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
		if (setterFactory != null) {
			builder.setterFactory(setterFactory);
		}
        //设置fallback
		Class<?> fallback = factory.getFallback();
		if (fallback != void.class) {
			return targetWithFallback(name, context, target, builder, fallback);
		}
        //设置fallbackFactory
		Class<?> fallbackFactory = factory.getFallbackFactory();
		if (fallbackFactory != void.class) {
			return targetWithFallbackFactory(name, context, target, builder,
					fallbackFactory);
		}
        //会调用Feign的target方法
		return feign.target(target);
	}

feign的target方法:

 public <T> T target(Target<T> target) {
      return build().newInstance(target);
    }

=========================================
//构建feign
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);
      //返回一个ReflectiveFeign feign对象
      return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
    }
  }

==============================================
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)));
      }
    }
    //生成 HystrixInvocationHandler对象
   //(InvocationHandler接口是proxy代理实例真实调用处理程序需要实现的一个接口,
   //每一个proxy代理实例都要有一个关联的InvocationHandler;在代理实例调用方法时,
   //方法调用被分派去调用InvocationHandler的invoke方法。)
    InvocationHandler handler = factory.create(target, methodToHandler);
   //通过jdk代理生成代理对象。
   //new Class<?>[] {target.type()}:一个interface数组,
   //声明了代理类实现了哪些接口,可以调用哪些方法(接口定义的所有方法)
    T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
        new Class<?>[] {target.type()}, handler);

    for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
      defaultMethodHandler.bindTo(proxy);
    }
    return proxy;
  }

这一段结束。

总结:通过@Autowired引入feign接口时,调用FeignClientFactoryBean getObject方法生成对应的代理类。

4.feign调用过程

当调用一个feign方法时,会调用HystrixInvocationHandler 类的invoke方法

public Object invoke(final Object proxy, final Method method, final Object[] args)
      throws Throwable {
。。。。。。。。。。。。。。
。。。。。。。。。。。。。。
    HystrixCommand<Object> hystrixCommand =
        new HystrixCommand<Object>(setterMethodMap.get(method)) {
          @Override
          protected Object run() throws Exception {
            try {
              //从dispatch中获取具体调用方法,然后调用SynchronousMethodHandler的invoke方法
              return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
            } catch (Exception e) {
              throw e;
            } catch (Throwable t) {
              throw (Error) t;
            }
          }
            
..................
..................
    return hystrixCommand.execute();
  }
SynchronousMethodHandler类的invoke方法:
public Object invoke(Object[] argv) throws Throwable {
    //创建RequestTemplate
    RequestTemplate template = buildTemplateFromArgs.create(argv);
    Options options = findOptions(argv);
    Retryer retryer = this.retryer.clone();
    while (true) {
      try {
         //主要方法
        return executeAndDecode(template, options);
      } catch (RetryableException e) {
        try {
          retryer.continueOrPropagate(e);
        } catch (RetryableException th) {
          Throwable cause = th.getCause();
          if (propagationPolicy == UNWRAP && cause != null) {
            throw cause;
          } else {
            throw th;
          }
        }
        if (logLevel != Logger.Level.NONE) {
          logger.logRetry(metadata.configKey(), logLevel);
        }
        continue;
      }
    }
  }

=====================================================
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
    //RequestTemplate转Request
    Request request = targetRequest(template);

    if (logLevel != Logger.Level.NONE) {
      logger.logRequest(metadata.configKey(), logLevel, request);
    }

    Response response;
    long start = System.nanoTime();
    try {
      //执行clent-->LoadBalancerFeignClient 的execute方法
      response = client.execute(request, options);
      // ensure the request is set. TODO: remove in Feign 12
      response = response.toBuilder()
          .request(request)
          .requestTemplate(template)
          .build();
    } catch (IOException e) {
      if (logLevel != Logger.Level.NONE) {
        logger.logIOException(metadata.configKey(), logLevel, e, elapsedTime(start));
      }
      throw errorExecuting(request, e);
    }
    long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);


    //解码
    if (decoder != null)
      return decoder.decode(response, metadata.returnType());

    CompletableFuture<Object> resultFuture = new CompletableFuture<>();
    asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
        metadata.returnType(),
        elapsedTime);

    try {
      if (!resultFuture.isDone())
        throw new IllegalStateException("Response handling not done");

      return resultFuture.join();
    } catch (CompletionException e) {
      Throwable cause = e.getCause();
      if (cause != null)
        throw cause;
      throw e;
    }
  }

LoadBalancerFeignClient 的execute方法:

方法1 :

factory--SpringClientFactory,是装载Ribbon BeanDefinition的容器,并加载RibbonClientConfiguration配置类。

最终会调用getBean,会调用:

方法 2 是获取具体server的地方:

调用ZoneAwareLoadBalancer的chooseServer方法,然后调用父类的chooseServer方法:

feign调用介绍到这里,Ribbon相关操作请查看Ribbon调用

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值