微服务之远程调用

打印 上一主题 下一主题

主题 924|帖子 924|积分 2772

前言

微服务的服务提供者和服务消费者解耦合之后,我们可以借助restTemplate这样的HTTP客户端,向微服务的服务提供者发起远程调用;
但是这样的代码有2大缺陷:

  • 代码可读性差,编程体验不统一
  • 当URL参数复杂时难以维护
  1. //使用RestTemplate发起远程调用
  2.     @Autowired
  3.     private RestTemplate restTemplate;
  4.     public Order findById(Long orderId) {
  5.         // 1.查询订单
  6.         Order order = orderMapper.selectById(orderId);
  7.         //2.调用user-service服务查询当前订单的用户信息
  8.         //String url = "http://127.0.0.1:8081/user/" + order.getUserId();
  9.         //使用RestTemplate发起远程调用
  10.         String url = "http://user-service/user/" + order.getUserId();
  11.         User user = restTemplate.getForObject(url, User.class);
  12.         //3.user封装到order对象
  13.         order.setUser(user);
  14.         // 4.返回
  15.         return order;
  16.     }
复制代码
 
一、Feign介绍

Feign是1个声明式的HTTP客户端,使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。
其作用就是帮助我们优雅的实现HTTP请求的发送,解决上面提到的问题。
而且Feign默认集成了Ribbon,所以使用Feign默认就实现了客户端负载均衡的效果。
 
二、Feign使用

1.引入依赖
  1. <dependency>
  2.     <groupId>org.springframework.cloud</groupId>
  3.     <artifactId>spring-cloud-starter-openfeign</artifactId>
  4. </dependency>
复制代码
 
2.添加@EnableFeignClients注解

在order-service的启动类添加注解开启Feign的功能;
  1. @MapperScan("com.zhanggen.order.mapper")
  2. @SpringBootApplication
  3. @EnableDiscoveryClient
  4. @EnableFeignClients //开启Feign
  5. public class OrderApplication {
  6.     public static void main(String[] args) {
  7.         SpringApplication.run(OrderApplication.class, args);
  8.     }<br>
  9.     @Bean
  10.     @LoadBalanced
  11.     public RestTemplate restTemplate() {
  12.         return new RestTemplate();
  13.     }
  14. }
复制代码
 
3.编写Feign的客户端

在order-service项目中com.zhanggen.order.mapper包下新建一个接口,内容如下:
  1. //FeignClient必须和@EnableFeignClients标注的类在同一个包下
  2. //该接口用于向user-service微服务发起远程调用
  3. //Feign底层默认使用HTTP协议发起远程调用
  4. //@FeignClient("user-service")+@GetMapping("/user/{id}")确定服务提供者的URL(http://user-service/user/{id})
  5. @FeignClient("user-service")
  6. public interface UserClient {
  7.     //根据userId查询用户信息
  8.     @GetMapping("/user/{id}")
  9.     User findById(@PathVariable Long id);
  10. }
复制代码
这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。
 
4.修改OrderService类

是不是看起来优雅多了。
  1. //使用Feign发起远程调用
  2.     @Autowired
  3.     private UserClient userClient;
  4.     public Order findById(Long orderId) {
  5.         // 1.查询订单
  6.         Order order = orderMapper.selectById(orderId);
  7.         //2.调用user-service服务查询当前订单的用户信息
  8.         //String url = "http://127.0.0.1:8081/user/" + order.getUserId();
  9.         //使用RestTemplate发起远程调用
  10.         //String url = "http://user-service/user/" + order.getUserId();
  11.         //User user = restTemplate.getForObject(url, User.class);
  12.         User user = userClient.findById(order.getUserId());
  13.         //3.user封装到order对象
  14.         order.setUser(user);
  15.         // 4.返回
  16.         return order;
  17.     }
复制代码
 
三、Feign配置

Feign可以支持很多的自定义配置,如下表所示:
类型作用说明feign.Logger.Level修改日志级别包含四种不同的级别:NONE(默认)、BASIC、HEADERS、FULL  NONE,不记录。默认选项 BASIC,仅记录请求方法和URL以及响应状态代码和执行时间。 HEADERS,记录基本信息以及请求和响应标头。 FULL,记录请求和响应的标题,正文和元数据。feign.codec.Decoder响应结果的解析器http远程调用的结果做解析,例如解析json字符串为java对象feign.codec.Encoder请求参数编码将请求参数编码,便于通过http请求发送,例如POST请求,将请求参数编码到请求体中feign.Contract支持的注解格式默认是SpringMVC的注解feign.Retryer失败重试机制请求失败的重试机制,默认是没有,不过会使用Ribbon的重试,例如A服务无法访问,会尝试访问集群中的B服务一般情况下,Feign的默认配置就能满足我们使用,如果要自定义配置时,只需要创建自定义的@Bean覆盖默认Bean即可。
下面以日志为例来演示如何自定义配置,修改Feign日志有 2 种方式: 配置文件方式、Java代码方式
1.配置文件方式(推荐)

基于配置文件修改feign的日志级别可以针对单个服务:
  1. feign:  
  2.   client:
  3.     config:
  4.       user-service: # 针对某个微服务的配置,也可以针对所有服务,这个位置换成default
  5.         loggerLevel: FULL #  日志级别
复制代码
2.Java代码方式

也可以基于Java代码来修改日志级别,在com.zhanggen.order.config包下创建类,然后声明一个Logger.Level的对象:
  1. package com.zhanggen.order.config;
  2. import feign.Logger;
  3. import org.springframework.context.annotation.Bean;
  4. public class FeignDefaultConfiguration  {
  5.     @Bean
  6.     public Logger.Level feignLogLevel(){
  7.         return Logger.Level.FULL; // 日志级别为FULL
  8.     }
  9. }
复制代码
2.1.配置局部

如果我想让以上日志配置在调用某1个服务提供者时生效,在FeigClien接口中修改如下;
  1. @FeignClient(value = "user-service",configuration = FeignDefaultConfiguration.class)
  2. public interface UserClient {
  3.     //根据userId查询用户信息
  4.     @GetMapping("/user/{id}")
  5.     User findById(@PathVariable Long id);
  6. }
复制代码
2.2.配置全局

如果我想让以上日志配置在调用任意服务提供者时生效,在启动类上修改如下;
  1. @EnableFeignClients(defaultConfiguration = FeignDefaultConfiguration.class)
  2. public class OrderApplication {
  3.     public static void main(String[] args) {
  4.         SpringApplication.run(OrderApplication.class, args);
  5.     }
复制代码
 
四、Feign连接池

Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:

  • URLConnection:默认实现,不支持连接池,每次请求都是新建连接
  • Apache HttpClient :支持连接池
  • OKHttp:支持连接池
因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。
1.pom引入依赖
  1. <dependency>
  2.     <groupId>io.github.openfeign</groupId>
  3.     <artifactId>feign-httpclient</artifactId>
  4. </dependency>
复制代码
2.application.yml配置

max-connections-per-route:再调用某1个服务提供者时,最多从连接池中拿出50个连接发起远程调用,避免服务雪崩;
  1. feign:
  2.   httpclient:
  3.     enabled: true # 开启feign对HttpClient的支持
  4.     max-connections: 200 # 设置最大的连接数
  5.     max-connections-per-route: 50 # 并行接收一个服务的请求数量
  6.    
复制代码
 
五、Feign公共模块

在微服务架构中肯定会存在多个服务消费者,这些服务消费者都需要借助Feign发起远程调用;
我们可以把Feign抽取出来作为1个公共模块以便于多个服务消费者使用;
 
 1.创建fein-api模块

把之前在order-service中编写的UserClient、User、FeignDefaultConfiguration剪切到feign-api项目中

2.pom依赖依赖

在fein-api模块中添加以下依赖
  1. <dependencies>
  2.         
  3.         <dependency>
  4.             <groupId>org.springframework.cloud</groupId>
  5.             <artifactId>spring-cloud-starter-openfeign</artifactId>
  6.         </dependency>
  7.         
  8.         <dependency>
  9.             <groupId>com.baomidou</groupId>
  10.             <artifactId>mybatis-plus-core</artifactId>
  11.             <version>3.4.0</version>
  12.         </dependency>
  13.         
  14.         <dependency>
  15.             <groupId>io.github.openfeign</groupId>
  16.             <artifactId>feign-httpclient</artifactId>
  17.         </dependency>
  18.     </dependencies>
复制代码
 
3.服务消费者

服务消费者依赖fei-api公共模块;
  1.   <dependency>
  2.       <groupId>com.zhanggen</groupId>
  3.      <artifactId>fein-api</artifactId>
  4.       <version>1.0-SNAPSHOT</version>
  5.   </dependency>
复制代码
 服务消费者启动类
  1. @EnableFeignClients(defaultConfiguration = FeignDefaultConfiguration.class,
  2.         basePackages = "com.zhanggen.feign")
  3. public class OrderApplication {
  4.     public static void main(String[] args) {
  5.         SpringApplication.run(OrderApplication.class, args);
  6.     }
  7.     //SpringBoot启动是,在Spring容器中放入1个restTemplate对象
  8.     @Bean
  9.     @LoadBalanced
  10.     public RestTemplate restTemplate() {
  11.         return new RestTemplate();
  12.     }
  13. }
复制代码
 
 
 
参考

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

小小小幸运

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表