目标
能够说出什么是 Feign
说出工作原理以及解决了什么问题
能够运用Feign实现远程服务调用
运用Feign实现微服务之间的调用
Feign-概述
• Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端配置。
• Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其封装,支持了SpringMVC注
解,让使用者更易于接受。
Feign也叫伪装:
Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。
1. Feign-快速入门
-
在消费端引入 open-feign 依赖
<!--feign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
parent中需要引入cloud依赖
<!--引入Spring Cloud 依赖--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
-
编写Feign调用接口
package com.ittest.consumer.feign; import com.ittest.consumer.config.FeignLogConfig; import com.ittest.consumer.domain.Goods; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * * feign声明式接口。发起远程调用的。 * String url = "http://FEIGN-PROVIDER/goods/findOne/"+id; Goods goods = restTemplate.getForObject(url, Goods.class); * * 1. 定义接口 * 2. 接口上添加注解 @FeignClient,设置value属性为 服务提供者的 应用名称 * 3. 编写调用接口,接口的声明规则 和 提供方接口保持一致。 * 4. 注入该接口对象,调用接口方法完成远程调用 */ @FeignClient(value = "FEIGN-PROVIDER") public interface GoodsFeignClient { @GetMapping("/goods/findOne/{id}") public Goods findGoodsById(@PathVariable("id") int id); }
-
在启动类 添加 @EnableFeignClients 注解,开启Feign功能
package com.ittest.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableDiscoveryClient // 激活DiscoveryClient @EnableEurekaClient @SpringBootApplication @EnableFeignClients //开启Feign的功能 public class ConsumerApp { public static void main(String[] args) { SpringApplication.run(ConsumerApp.class,args); } }
-
测试调用
package com.ittest.consumer.controller; import com.ittest.consumer.domain.Goods; import com.ittest.consumer.feign.GoodsFeignClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/order") public class OrderController { @Autowired private RestTemplate restTemplate; @Autowired private GoodsFeignClient goodsFeignClient; @GetMapping("/goods/{id}") public Goods findGoodsById(@PathVariable("id") int id){ Goods goods = goodsFeignClient.findGoodsById(id); return goods; } }
注意
①Feign接口中的方法名及请求类型要与被调用方保持一致
②Feign接口中的@PathVariable(“id”) 中(“id”)不可以省略,否则会报 java.lang.IllegalStateException: PathVariable annotation was empty on param 0.
③Feign接口中返回值如果是类,类必须要有无参构造,否则会报 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.ittest.consumer.domain.Goods
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
2. Feign-超时配置
# 设置Ribbon的超时时间
ribbon:
ConnectTimeout: 1000 # 连接超时时间 默认1s
ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
3. Feign-日志记录
①设置日志级别,只支持debug
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
com.ittest: debug
②声明feign的配置类
package com.ittest.consumer.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignLogConfig {
/*
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL;记录完成的请求 响应数据
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
③启用bean @FeignClient(configuration = XxxConfig.class)
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}