OpenFeign服务调用

目录

 

0 环境

1 前言

2 尝鲜

2.1 创建springboot项目

2.2 yml配置

2.3 启动类配置

2.4 接口配置

2.5 接口调用

2.6 测试结果

3 参数传递

3.1 导入依赖模块

3.2 接口配置

3.3 接口调用

3.4 测试结果

3.5 小结

4 继承特性

4.1 新建maven子模块

4.2 封装接口

4.3 消费者和openfeign添加依赖

4.4 提供者实现接口

4.5 openfeign配置

4.6 小结

5 数据压缩

6 日志配置

6.1 在yml中配置日志级别

6.2 两种配置日志bean方式

7 openfeign+hystrix配合使用

8 小结


0 环境

系统环境:win10
编辑器:idea
springcloud版本:H版

1 前言

之前使用的eureka/hystrix 都是调用RestTemplate(繁琐 重复高) OpenFeign对请求进行简化。Feign停更了 OpenFeign是在Feign基础上开发出来的

  • 常用的几种接口调用方法
  • Httpclient 易用 灵活
  • Okhttp 处理网络请求 轻量级 支持多协议。。
  • HttpURLConnection 使用复杂
  • RestTemplate Rest服务的客户端 提供多种便携访问HTTP服务的方法

2 尝鲜

2.1 创建springboot项目

在这里插入图片描述

2.2 yml配置

spring:
  application:
    name: openfeign
 
 
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1234/eureka
 
server:
  port: 5000
 

2.3 启动类配置

@EnableFeignClients --> 开启Feign在这里插入图片描述

2.4 接口配置

使用的是之前的eureka server和provider以及如今使用的openfeign

// openfeign service
// 对比之前xxx.getForObject("http://provider/hello1", String.class)
// 现在只需要抽取provider hello1 拼接不需要我们操心了
@FeignClient("provider")
public interface HelloService {
@GetMapping("/hello")
// 方法名无所谓 无参调用
String hello();
} 

2.5 接口调用


	@RestController

	public class HelloController {

	@Autowired

	HelloService helloService;

	


	// 无参测试

	@GetMapping("/hello")

	public String hello(){

	return helloService.hello();

	}

	} 

2.6 测试结果

开启eureka server provider openfeign
在这里插入图片描述

3 参数传递

3.1 导入依赖模块

因为要用到类 之前新建一个模块 现在该opfeign需要引入依赖 可以在opfeign中定义类(随意

<dependency>
<groupId>xxx</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

3.2 接口配置


	// eureka provider

	@RestController

	public class HelloController {

	


	@GetMapping("/hello1")

	public String hello1(String name){

	return "hello provider: " + name;

	}

	


	@PostMapping("/user1")

	public User addUser1(@RequestBody User user){

	return user;

	}

	


	@DeleteMapping("/user1/{id}")

	public void delUser1(@PathVariable Integer id){

	System.out.println("json形式:" + id);

	}

	


	@GetMapping("/user2")

	public void getUserByName(@RequestHeader String name) throws UnsupportedEncodingException {

	// 解码

	System.out.println(URLDecoder.decode(name, "utf-8"));

	}

	} 

	// openfeign service配置

	@FeignClient("provider")

	public interface HelloService {

	// 参数传递一定要绑定参数名

	@GetMapping("/hello1")

	String hello1(@RequestParam("name") String name);

	


	// json

	// 注:key/value形式的参数 一定要标记参数的名称

	@PostMapping("/user1")

	User user1(@RequestBody User user);

	


	// 删除id

	// /user1/{id}

	@DeleteMapping("/user1/{id}")

	void delUser1(@PathVariable Integer id);

	


	// 通过header来传参 中文要转码

	@GetMapping("/user2")

	void getUserByName(@RequestHeader String name);

	


	}

3.3 接口调用

// openfeign controller 传参
@GetMapping("/hello1")
public void hello1() throws UnsupportedEncodingException {
String s = helloService.hello1("你好呀");
System.out.println("hello1:" + s);
System.out.println("---------------------------------------");
User user = new User();
user.setId(1);
user.setName("小个");
user.setNickName("萨达过");
User user1 = helloService.user1(user);
System.out.println("user:" + user1);
System.out.println("---------------------------------------");
helloService.delUser1(1);
System.out.println("---------------------------------------");
// 放在heard中的中文参数 一定要先编码在传递
helloService.getUserByName(URLEncoder.encode("方便热土", "utf-8"));


}
 

3.4 测试结果

开启eureka server provider openfeign
在这里插入图片描述

3.5 小结

  • 参数传递
  • 参数一定要绑定参数名
  • 若通过header来传递参数 中文需转码 编码后在传递(URLEncoder.encode(xxx, "utf-8"))
    .provider解码(URLDecoder.decode(xxx, "utf-8"))

4 继承特性

4.1 新建maven子模块

这个包被其他模块依赖 需要springmvc依赖


	<dependencies>

	<!-- 涉及到springmvc -->

	<dependency>

	<groupId>org.springframework.boot</groupId>

	<artifactId>spring-boot-starter-web</artifactId>

	<version>2.2.5.RELEASE</version>

	</dependency>

	


	<!-- 存储类模块 -->

	<dependency>

	<groupId>xxx</groupId>

	<artifactId>commons</artifactId>

	<version>1.0-SNAPSHOT</version>

	</dependency>

	


	</dependencies>

4.2 封装接口

public interface IUserService {
@GetMapping("/hello")
String hello();


// 参数传递一定要绑定参数名 若是参数最好用@RequestParam
// 最好别用map 其问题是可以随意传参
@GetMapping("/hello1")
String hello1(@RequestParam("name") String name);


// json
// 注:key/value形式的参数 一定要标记参数的名称
@PostMapping("/user1")
User addUser1(@RequestBody User user);


// 删除id
// /user1/{id}
// 添加@PathVariable("id") 注意了一定要把("id")添加进去 不然会报错
@DeleteMapping("/user1/{id}")
void delUser1(@PathVariable("id") Integer id);


// 通过header来传参 中文要转码
// 添加@RequestHeader("name") 注意了一定要把("name")添加进去 不然会报RequestHeader0参数错
@GetMapping("/user2")
void getUserByName(@RequestHeader("name") String name) throws UnsupportedEncodingException;
}

4.3 消费者和openfeign添加依赖

<dependency>
<groupId>com.sundown</groupId>
<artifactId>commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>


<dependency>
<groupId>com.sundown</groupId>
<artifactId>hi-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

4.4 提供者实现接口

 
 @RestController
 //@RequestMapping("/test")
 public class Hello1Controller implements IUserService {
  
 @Value("${server.port}")
 Integer port;
  
 // 重写
 @Override
 public String hello(){
 return "hello provider:" + port;
 }
  
  
 /**
 * @Description: consumer访问该接口 调用RestTemplate的get请求
 * @Param: [name]
 * @return: java.lang.String
 * @Author: 水面行走
 * @Date: 2020/3/4
 */
 @Override
 public String hello1(String name){
 return "hello provider: " + name;
 }
  
 @GetMapping("/hello2")
 public String hello2(String name){
 System.out.println(new Date() + "--->" + name);
 return "hello " + name;
 }
  
 // 在provider 提供2个post接口
  
 /**
 * @Description: key:value形式传参
 * @Param: [user]
 * @return: model.User
 * @Author: 水面行走
 * @Date: 2020/3/7
 */
 @PostMapping("/user")
 public User addUser(User user){
 return user;
 }
  
  
 /**
 * @Description: json形式传参
 * @Param: [user]
 * @return: model.User
 * @Author: 水面行走
 * @Date: 2020/3/7
 */
 @Override
 public User addUser1(@RequestBody User user){
 return user;
 }
  
 /**
 * @Description: k/v形式 因为是更新操作 put方法返回为void 所以返回值为void就行 有返回值不会报错
 * @Param:
 * @return:
 * @Author: 水面行走
 * @Date: 2020/xx/xx
 */
 @PutMapping("/update-user")
 public void updateUser(User user){
 System.out.println("k/v形式:" + user);
 }
  
 /**
 * @Description: json形式 别忘了传参添加注解 因为是更新操作 put方法返回为void 所以返回值为void就行 有返回值不会报错
 * @Param:
 * @return:
 * @Author: 水面行走
 * @Date: 2020/xx/xx
 */
 @PutMapping("/update-user1")
 public void updateUser1(@RequestBody User user){
 System.out.println("json形式:" + user);
 }
  
 /**
 * @Description: k/v形式的删除 xxx?id=1
 * @Param:
 * @return:
 * @Author: 水面行走
 * @Date: 2020/3/8
 */
 @DeleteMapping("/deluser")
 public void delUser(Integer id){
 System.out.println("k/v形式:" + id);
 }
  
 /**
 * @Description: PathVariable(参数放在路径中 xxx/1)形式的删除
 * @Param:
 * @return:
 * @Author: 水面行走
 * @Date: 2020/3/8
 */
 @Override
 public void delUser1(@PathVariable Integer id){
 System.out.println("json形式:" + id);
 }
  
 @Override
 public void getUserByName(@RequestHeader String name) throws UnsupportedEncodingException {
 // 解码
 System.out.println(URLDecoder.decode(name, "utf-8"));
 }
 }

4.5 openfeign配置

 
 // 继承接口
 // 继承特性的好处:抽出公共模块 provider和consumer代码一致 只需更改公共接口即可 减少出错率
 // 坏处就是耦合度变高
 @FeignClient("provider")
 public interface Hello1Service extends IUserService {
  
 }
 
 // 调用Hello1Service
 // 其他这个类没有变化 调用结果和上次是一致的
 @RestController
 public class Hello1Controller {
 @Autowired
 Hello1Service hello1Service;
  
 // 无参测试
 @GetMapping("/hello")
 public String hello(){
 return hello1Service.hello();
 }
  
 // 传参
 @GetMapping("/hello1")
 public void hello1() throws UnsupportedEncodingException {
 String s = hello1Service.hello1("你好呀");
 System.out.println("hello1:" + s);
 System.out.println("---------------------------------------");
 User user = new User();
 user.setId(1);
 user.setName("小个");
 user.setNickName("萨达过");
 User user1 = hello1Service.addUser1(user);
 System.out.println("user:" + user1);
 System.out.println("---------------------------------------");
 hello1Service.delUser1(1);
 System.out.println("---------------------------------------");
 // 放在heard中的中文参数 一定要先编码在传递
 hello1Service.getUserByName(URLEncoder.encode("个百分点", "utf-8"));
  
 }
  
 }

4.6 小结

  • 继承特性
  • 代码简洁 服务者和消费者指向同一目标 一改都改 出错烦恼大减(既是优点也是缺点(耦合度高) 类似赤壁之战 曹操的战船相连)
  • 无论是否继承 参数(无参还是传参方式依然不变)

5 数据压缩

开启压缩 节省资源 提升性能

 
 feign:
 compression:
 request:
 # 开启数据压缩请求
 enabled: true
 # 压缩数据类型
 mime-types: text/xml, application/xml, application/json
 # 数据压缩下限 2048表示传输数据大于2048 才会进行数据压缩(最小压缩值标准)
 min-request-size: 2048
 # 开启数据压缩响应
 response:
 enabled: true

在这里插入图片描述在这里插入图片描述

6 日志配置

  • 配置日志 分4种
  1. NONE: 不开启日志(默认)
  2. BASIC: 记录请求方法、URL、响应状态、执行时间
  3. HEADERS: 在BASIC基础上 加载请求/响应头(+2)
  4. FULL: 在HEADERS基础上 增加body和请求元数据(+3)

6.1 在yml中配置日志级别

 
 # 可以在yml feign.client.config.xxx 配置超时时间 拦截器等配置
 logging:
 level:
 com.sundown.openfeign: debug

6.2 两种配置日志bean方式

  • 在applicaton类中配置bean
 
 import feign.Logger;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
  
 @SpringBootApplication
 @EnableFeignClients
 public class OpenfeignApplication {
  
 public static void main(String[] args) {
 SpringApplication.run(OpenfeignApplication.class, args);
 }
  
 // 配置日志 分4种
 // 1. NONE: 不开启日志(默认)
 // 2. BASIC: 记录请求方法、URL、响应状态、执行时间
 // 3. HEADERS: 在BASIC基础上 加载请求/响应头(+2)
 // 4. FULL: 在HEADERS基础上 增加body和请求元数据(+3)
 // 通过bean配置
 @Bean
 Logger.Level loggerLevel(){
 return Logger.Level.FULL;
 }
 }
  • Configuration中配置

正好将超时和自定义拦截器加入

 
 @Configuration
 public class FeignConfig {
 // 超时时间配置(通过Options可配置连接超时时间和读取超时时间)
 // Options第一个参数连接超时时间(ms 默认1000*10)
 // Options第二个参数取超时时间(ms 默认1000*60)
 @Bean
 public Request.Options options(){
 return new Request.Options(3000, 8000);
 }
  
 /**
 * 日志级别
 * 在这里配置日志级别
 * @return
 */
 @Bean
 Logger.Level feignLoggerLevel() {
 return Logger.Level.FULL;
 }
  
 // 配置basic认证
 // 通常: 调用有权限控制的接口 可能认证的值通过传参/请求头去传认证信息
 @Bean
 public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
 return new BasicAuthRequestInterceptor("user", "password");
 }
  
 // 自定义拦截器配置
 @Bean
 public FeignBasicAuthRequestInterceptor feignBasicAuthRequestInterceptor() {
 return new FeignBasicAuthRequestInterceptor();
 }
 }
 
 // OpenFeign自定义拦截器(自定义认证方式) 实现RequestInterceptor
 // 自定义一个请求拦截器 在请求之前做认证操作 在往请求头中配置认证后的信息
 public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
  
 // 业务逻辑
 @Override
 public void apply(RequestTemplate requestTemplate) {
 System.err.println("欢迎进入拦截器: " + requestTemplate);
 }
 }
 
 // 在openfeign service层配置
 //@FeignClient(value = "provider",configuration= FeignConfig.class) 配置类-->拦截器啥的
 @FeignClient(value = "provider",configuration= FeignConfig.class)
 public interface Hello1Service extends IUserService {
  
 }

启动eureka server和provider 还有openfeign http://localhost:5000/hello1
在这里插入图片描述
在这里插入图片描述

7 openfeign+hystrix配合使用

降级@FeignClient+value+fallback/fallbackFactory属性(都是在openfeign模块中实现 且要开启hystrix)

 
 hystrix:
 # 开启hystrix
 enabled: true
  • 降级fallback属性
 
 // fallback属性实现类
 @Component
 @RequestMapping("/milk") // implements Hello1Service相当于调用了2次 避免重复的请求地址 不然会报错
 public class HelloServiceFallback implements Hello1Service{
  
 @Override
 public String hello() {
 return "error-hello";
 }
  
 @Override
 public String hello1(String name) {
 return "error-hello1";
 }
  
 @Override
 public User addUser1(User user) {
 return null;
 }
  
 @Override
 public void delUser1(Integer id) {
  
 }
  
 @Override
 public void getUserByName(String name) throws UnsupportedEncodingException {
  
 }
 }
 
 @FeignClient(value = "provider",fallback= HelloServiceFallback.class)
 public interface Hello1Service extends IUserService {
  
 }

启动/重启eureka server和openfeign 断开provider http://localhost:5000/hellohttp://localhost:5000/hello1
在这里插入图片描述
在这里插入图片描述

  • 降级fallbackFactory属性
 
 @Component
 public class HelloServiceFallFactory implements FallbackFactory<Hello1Service> {
  
 @Override
 public Hello1Service create(Throwable throwable) {
 return new Hello1Service() {
 @Override
 public String hello() {
 return "error1---------";
 }
  
 @Override
 public String hello1(String name) {
 return "error2---------";
 }
  
 @Override
 public User addUser1(User user) {
 return null;
 }
  
 @Override
 public void delUser1(Integer id) {
  
 }
  
 @Override
 public void getUserByName(String name) throws UnsupportedEncodingException {
  
 }
 };
 }
 }
  
 
 //@FeignClient(value = "provider",fallback= HelloServiceFallback.class) fallback和fallbackFactory不能同时使用
 @FeignClient(value = "provider",fallbackFactory= HelloServiceFallFactory.class)
 public interface Hello1Service extends IUserService {
  
 }

启动/重启eureka server和openfeign 断开provider http://localhost:5000/hellohttp://localhost:5000/hello1
在这里插入图片描述
在这里插入图片描述

8 小结

  • openfeign只需要我们提供关键的value就行了 自行拼接
  • openfeign环境: 依赖eureka连接依赖 web openfeign
  • yml eureka连接配置
  • 注解开启openfeign
  • 无参 无需参数直接调用即可
  • 有参 --> 绑定参数、header传递 中文要解码、多参数的话 建议@RequestParam("xxx")
  • 特性继承 --> provider和openfeign公用一个接口 特别注意(一定要定义名字@RequestHeader("xxx") @PathVariable("xxx")。。。不然会报错) 它的好处既是坏处
  • 数据压缩 yml配置 开启压缩请求和响应 最小压缩值标准还有压缩类型
  • 日志配置 四种级别NONE BASIC HEADERS FULL
  • yml --> logging: level: com.sundown.openfeign: debug
  • 在bean配置 要么在application中或是在config中配置好(还可以超时配置和认证配置或自定义拦截器) 在@FeignClient中配置configuration属性 例如@FeignClient(value = "provider",configuration= FeignConfig.class)
  • 另外 也可在yml feign.client.config.xxx 配置超时时间 拦截器等
  • openfeign+hystrix降级操作 在yml中开启hystrix 在@FeignClient中实现fallbackFactory属性(需要implements FallbackFactory<T>)或fallback(实现接口implements Hello1Service添加@RequestMapping("/xx")作为区分) 2种实现方式都要添加@Component注解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值