feign的底层实现为io.github.openfeign
springcloud整合了底层实现,同时整合的还有ribbon与hystrix
本文描述了springcloud如何对openfeign进行整合的
一、原生的openfeign
不用springcloud-openfeign,直接使用openfeign的方式
根据官方示例:
public interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repository);
class Contributor {
String login;
int contributions;
}
}
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
github.contributors("OpenFeign", "feign");
由于不用spring,需要手动创建调用对象,无法使用注入了。
先创建Feign.Builder对象,再通过Builder::target方法创建了具体的对象
T target(Class<T> apiType, String url)
<T> T target(Target<T> target)
target方法有两种传参方式,官方示例中用到的是第一个,在springcloud中,用了第二个方法,构件了Target对象去调用的。
二、springcloud中使用openfeign
1、入口类中添加注解@EnableFeignClients,可以添加一些参数。
2、创建接口类,同Controller一样的注解
@FeignClient(name="xx")
public interface Hello{
@GetMapper("test")
String xx(@RequestParam("f") String f);
}
3、注入,并调用
@Resource
private Hello hello;
hello.xx("f");
三、springcloud实现openfeign
1、spring如何发现feignClient的
spring提供了一个接口类,用于拓展spring,支持将自定义的注解类,加载到spring容器中;比如实现@Service、@Controller一类的功能。
这个接口就是ImportBeanDefinitionRegistrar。
FeignClientsRegistrar 实现了 ImportBeanDefinitionRegistrar接口
在接口方法registerBeanDefinitions中,进行了如下操作:
a、发现与注册默认配置;找到@EnableFeignClients注解,收集该注解的参数。
b、发现与注册feignClient;扫描路径找到@FeignClient注解的类,提取configuration属性注册成配置,其他数据注册到别名为contextId+FeignClient的Bean
2、实例化代理类
spring的FactoryBean,是用于创建某一类型的Bean,允许我们自定义Bean的创建过程。
FeignClientFactoryBean 实现了 FactoryBean
该类中就自定义了实体类的创建过程,等同于上面的io.github.openfeign的官方示例
先创建Feign.Builder
然后判断是否有配置url参数,若配置了url,直接调用feign,不走负载平衡
若没有url, 创建ribbon包下的LoadBalancerFeignClient,具有负载平衡特性的feignClient, 将client保存到对应builder中
在调用builder::target方法,创建实例之前,通过HystrixTargeter类,处理了fallback相关功能,也就是hystrix的熔断器功能,处理完之后,最后调用target方法,创建实例。
3、调用接口
原生的openfeign下的ReflectiveFeign 具体实例化了代理类
代理类具体的功能是创建了一个map,用户编写的feignClient接口的Method作为key,MethodHandler作为value(实现类SynchronousMethodHandler);
MethodHandler实际绑定了对应的client,就是前面提到的存入到builder中的LoadBalancerFeignClient;
最终执行execute调用接口,execute中通过ribbon实现了负载平衡