一、Feign的介绍
Feign是一个声明式 WebService 客户端,使用Feign能够让编写Web Service 客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。Feign也支持可插拔式的编码器和解码器。
Spring Cloud 对 Fiegn 进行了封装,使其支持了Spring MVC 标准注解和HttpMessageConverts。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
前面使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法,但是在实际的开发中,由于对服务依赖的调用可能不止一处。往往一个接口会被多处调用,所以通常会对每个微服务自行封装一些客户端类来包装依赖服务的调用,所以Feign在此基础上做了进一步封装,由它来帮助我们自定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置他(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成服务提供放的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户端的开发量。
二、Feign的使用
1. 在 microservicecloud-api 工程增加pom依赖和代码
(1) 添加feign依赖
<!-- feign相关 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
(2) 新建DeptClientService接口并且添加@FeignClient注解
@FeignClient(value = "microservicecloud-dept") public interface DeptClientService { @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(@RequestBody Dept dept); @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) public Dept get(@PathVariable("id") Long id); @RequestMapping(value = "/dept/get/list", method = RequestMethod.GET) public List<Dept> list(); }
@FeignClient的参数说明
- name(或value):指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
- url: url一般用于调试,可以手动指定@FeignClient调用的地址,上生产不需要
- decode404:当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException
- configuration: Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract
- fallback: 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口
- fallbackFactory: 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码
- path: 定义当前FeignClient的统一前缀
2. 参考microservicecloud-consumer-dept-80,新建一个消费者项目(Feign):microservicecloud-consumer-dept-feign
(1) pom.xml依赖
<dependencies> <!-- 引入自己定义的api通用包,可以使用Dept部门Entity --> <dependency> <groupId>com.linhw.demo</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <!-- web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!-- eureka client --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- eureka config --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- ribbon --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <!-- feign相关 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
(2) 在主启动类中添加@EnableFeignClients注解
@SpringBootApplication @EnableEurekaClient @EnableFeignClients(basePackages={"com.linhw.demo.feign"}) public class DeptConsumer80_Feign_App { public static void main(String[] args) { SpringApplication.run(DeptConsumer80_Feign_App.class, args); } }
(3) Controller中使用@Autowired直接注入上面定义的 DeptClientService接口对应的实例
@RestController @RequestMapping("/consumer") public class DeptController_Consumer { @Autowired private DeptClientService deptClientService; @RequestMapping(value = "/dept/add") public boolean add(Dept dept) { return deptClientService.add(dept); } @RequestMapping(value = "/dept/get/{id}") public Dept get(@PathVariable("id") Long id) { return deptClientService.get(id); } @RequestMapping(value = "/dept/list") public List list() { return deptClientService.list(); } }
(4) 先启动eureka集群,再启动3个生产者服务,最后启动本服务
在浏览器中打开:http://localhost/consumer/dept/get/1,可以看到轮询调用了3个生产者服务