用法
定义好接口,在integration层的接口中,用@FeignClient进行注解。
@FeignClient(value = DependServiceConstants.RFP_CORE_SERVICE_NAME)
public interface ApproveServiceClient {
@org.springframework.web.bind.annotation.PostMapping({"apply/{applyType}/{applyId}"})
ResultDTO<java.lang.Boolean> approveApply(@org.springframework.web.bind.annotation.PathVariable("applyType") java.lang.Integer integer, @org.springframework.web.bind.annotation.PathVariable("applyId") java.lang.Long aLong, @org.springframework.web.bind.annotation.RequestBody ApproveApplyReq approveApplyReq);
}
在Application入口,用@EnableFeignClients注解。
实现
在Feign实现粗读中解释了最原始的Feign是如何实现的Http调用的。下面来看看框架是如何对Feign进一步封装的。
先从注解 @EnableFeignClients 入手。其有一个@Import注解,引入的是FeignClientsRegistrar。从名字可看出,他应该就是把FeignClient注解的对象注入到Spring容器的类。
其类图如下:
看其对接口ImportBeanDefinitionRegistrar的实现:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
方法registerDefaultConfiguration是将EnableFeignClients的默认配置进行注入,如果有的话。
方法registerFeignClients就是对所有有FeignClient注解的类进行注入的过程。
注入过程不详细列出来了。注意一点是,它向容器注入的是org.springframework.cloud.netflix.feign.FeignClientFactoryBean。
我们知道FactoryBean是Bean的工厂,在获取Bean的实例的时候,实际是调用FactoryBean.getObject来得到的。
@Override
public Object getObject() throws Exception {
FeignContext context = applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
if (!StringUtils.hasText(this.url)) {
String url;
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
}
else {
url = this.name;
}
url += cleanPath();
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, 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 lod 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 targeter.target(this, builder, context, new HardCodedTarget<>(
this.type, this.name, url));
}
上面是对Url进行处理的过程。最下面Targeter.target最终是调用了Feign.newInstance(Target)。