源码地址:https://gitee.com/datadogapache/dashboard/projects
一、什么是Feign
Feign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求。
Spring Cloud的声明式调用, 可以做到使用 HTTP请求远程服务时能就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。Feign的应用,让Spring Cloud微服务调用像Dubbo一样,Application Client直接通过接口方法调用Application Service,而不需要通过常规的RestTemplate构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。
二、Feign工作原理
1、 启动类添加@EnableFeignClients注解,Spring会扫描标记了@FeignClient注解的接口,并生成此接口的代理对象
2、 @FeignClient(value = "XC_SERVICE_MANAGE_CMS")即指定了cms的服务名称,Feign会从注册中心获取cms服务列表,并通过负载均衡算法进行服务调用。
3、在接口方法中使用注解@GetMapping("/cms/page/get/{id}"),指定调用的url,Feign将根据url进行远程调用。
-
主程序入口添加了@EnableFeignClients注解开启对FeignClient扫描加载处理。根据Feign Client的开发规范,定义接口并加@FeignClient注解。
-
当程序启动时,回进行包扫描,扫描所有@FeignClients的注解的类,并且讲这些信息注入Spring IOC容器中,当定义的的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate.当生成代理时,Feign会为每个接口方法创建一个RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象可封装HTTP请求需要的全部信息,如请求参数名,请求方法等信息都是在这个过程中确定的。
-
然后RequestTemplate生成Request,然后把Request交给Client去处理,这里指的时Client可以时JDK原生的URLConnection,Apache的HttpClient,也可以时OKhttp,最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡进行微服务之间的调用。
三、@FeignClient解析
@FeignClient注解主要被@Target({ElementType.TYPE})修饰,表示该注解主要使用在接口上。它具备了如下的属性:
-
name:指定FeignClient的名称,如果使用了Ribbon,name就作为微服务的名称,用于服务发现。
-
url:url一般用于调试,可以指定@FeignClient调用的地址。
-
decode404: 当发生404错误时,如果该字段为true,会调用decoder进行解码,否则抛出FeignException.
-
configuration:Feign配置类,可以自定或者配置Feign的Encoder,Decoder,LogLevel,Contract。
-
fallback:定义容错的处理类,当调用远程接口失败或者超时时,会调用对应的接口的容错逻辑,fallback指定的类必须实现@Feign标记的接口。
-
fallbacjFactory:工厂类,用于生成fallback类实例,通过这个属性可以实现每个接口通用的容错逻辑们介绍重复的代码。
-
path:定义当前FeignClient的统一前缀。
四、建立一个生产者和消费者
1、建立生产者
package com.example.springcloudfeign.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin
public class ProducerController {
@RequestMapping("123")
String Producer(){
return "hello,welcome to connect me!";
}
}
2、建立消费者
package com.example.springcloudfeign.Server;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "user")
public interface Consumer {
@RequestMapping("/123")
String test();
}
3、配置微服务以及微服务的调用接口
package com.example.springcloudfeign.Controller;
import com.example.springcloudfeign.Server.Consumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin
public class ConsumerController {
@Autowired
Consumer consumer;
@RequestMapping("789")
String consumerTest(){
return consumer.test();
}
}
4、启动类添加@EnableDiscoveryClient 开启Nacos,添加@EnableFeignClients开启Fegin客户端,注入SpringIoc容器
package com.example.springcloudfeign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class SpringcloudfeignApplication {
public static void main(String[] args)
{
SpringApplication.run(SpringcloudfeignApplication.class, args);
}
}
五、测试调用
浏览器输入http://localhost:8090/789,其中消费者端口为8090,生产者端口为8089,访问消费者接口,可调用生产者的方法输出结果。
单独调用消费者接口输出结果如下
可见调用生产者和消费者的输出结果一致,也就验证了调用消费者接口时实际是调用生产者接口。