一、概述
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。使用参考
Feign旨在使编写Java Http客户端变得更容易。前面在使用 Ribbon + RestTemplate 时,利用RestTemplate对Http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由它来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(类似于在Dao接口上面标注@Mapper注解),即可完成对服务提供方的接口绑定,简化了使用SpringCloud Ribbon 时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon,利用Ribbon维护了微服务的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法优雅而简单的实现了服务调用。
总结
:
①Feign是Webservice客户端
②Ribbon是通过微服务名字获取调用地址,Feign是通过接口+注解(类似于mybatis注解版)获取微服务的调用地址,是一种面向接口编程的套路
二、Feign工程搭建
1、参考microservicecloud-consumer-dept-80工程新建工程microservicecloud-consumer-dept-feign
2、复制microservicecloud-consumer-dept-80工程中的pom依赖至microservicecloud-consumer-dept-feign
<dependency><!-- 自己定义的api -->
<groupId>com.atguigu.springcloud</groupId>
<artifactId>microservicecloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
3、添加Feign启动器依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
4、复制microservicecloud-consumer-dept-80工程中的主配置文件至microservicecloud-consumer-dept-feign:注意修改应用端口
server:
port: 8080
eureka:
client:
register-with-eureka: false #服务消费者端不提供服务,不必将应用注册至Eureka
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
5、修改依赖工程microservicecloud-api的pom文件,添加Feign启动器依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
6、在工程microservicecloud-api中新建DeptClientService接口并使用注解@FeignClient:之所以把这个接口放在了microservicecloud-api工程中,是因为有可能有多个消费者端需要使用DeptClientService ,虽然这对于服务提供者端是多余的;该接口在定义时也指明了针对的是注册至Eureka的哪个微服务(value属性的值),以及具体的哪个接口(mapping的映射),在消费者调用某个接口的时候会根据该微服务找到对应的服务器(可能有多台,这时会进行负载均衡)调用具体的接口实现,这说明Feign有类似于Mybatis的功能会为标注的接口生成实现,这样在消费者端只需要面向该接口编程即可
@FeignClient(value = "MICROSERVICECLOUD-DEPT")
public interface DeptClientService {
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
public Dept get(@PathVariable("id") long id);
@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
public List<Dept> list();
@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
public boolean add(Dept dept);
}
7、对工程microservicecloud-api执行mvn clean和mvn install命令,保证刚才的改动对引用者生效
8、在microservicecloud-consumer-dept-feign工程中创建controller,使用microservicecloud-api定义的DeptClientService 接口
@RestController
public class DeptController_Consumer {
@Autowired
private DeptClientService service;
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id) {
return this.service.get(id);
}
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list() {
return this.service.list();
}
@RequestMapping(value = "/consumer/dept/add")
public Object add(Dept dept) {
return this.service.add(dept);
}
}
9、microservicecloud-consumer-dept-feign工程修改主启动类,使用@EnableFeignClients注解开启Feign功能:
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class DeptConsumer80_Feign_App {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}
10、启动测试:发现Feign自带负载均衡,默认采用轮询的方式进行负载
总结
:Feign通过面向接口的方式调用Rest服务(之前是Ribbon + RestTemplate),将请求发送给Eureka服务器,通过Eureka找到服务提供者实例列表,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡。
三、调用流程
1、服务提供者在应用启动时将应用注册至Eureka,注册时会产生一个微服务名称
2、Feign的客户端通过订阅该微服务(以微服务名区分订阅的服务,即@FeignClient注解的value属性),来完成服务提供者具体接口的中转(RequestMapping的映射)
3、消费者端通过启用Feign功能(@EnableFeignClients)来调用Feign客户端声明的接口,调用时会通过Feign转至Eureka,最终调用到服务提供者提供的REST服务
猜测
:
①Feign只是通过FeignClient做了一个服务调用的中转,其底层应该是通过Ribbon实现的,也就是说Feign是在Ribbon的基础之上做了进一步的封装,将服务的调用转化为了面向接口的方式。而Ribbon在服务调用时很直接,直接使用RestTemplate调用服务。
②如果Feign的底层通过Ribbon实现,那么在进行负载均衡算法的切换时和Ribbon就完全相同