• 微服务之同步远程调用


    前言

    微服务的服务提供者和服务消费者解耦合之后,我们可以借助restTemplate这样的HTTP客户端,向微服务的服务提供者发起远程调用;

    但是这样的代码有2大缺陷:

    • 代码可读性差,编程体验不统一

    • 当URL参数复杂时难以维护

     //使用RestTemplate发起远程调用
        @Autowired
        private RestTemplate restTemplate;
        public Order findById(Long orderId) {
            // 1.查询订单
            Order order = orderMapper.selectById(orderId);
            //2.调用user-service服务查询当前订单的用户信息
            //String url = "http://127.0.0.1:8081/user/" + order.getUserId();
            //使用RestTemplate发起远程调用
            String url = "http://user-service/user/" + order.getUserId();
            User user = restTemplate.getForObject(url, User.class);
            //3.user封装到order对象
            order.setUser(user);
            // 4.返回
            return order;
        }

    一、Feign介绍

    Feign是1个声明式的HTTP客户端,使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可

    其作用就是帮助我们优雅的实现HTTP请求的发送,解决上面提到的问题。

    而且Feign默认集成了Ribbon,所以使用Feign默认就实现了客户端负载均衡的效果

    二、Feign使用

    1.引入依赖

    <!--feign的依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

    2.添加@EnableFeignClients注解

    在order-service的启动类添加注解开启Feign的功能;

    @MapperScan("com.zhanggen.order.mapper")
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients //开启Feign
    public class OrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }

    3.编写Feign的客户端

    在order-service项目中com.zhanggen.order.mapper包下新建一个接口,内容如下:

    //FeignClient必须和@EnableFeignClients标注的类在同一个包下
    //该接口用于向user-service微服务发起远程调用
    //Feign底层默认使用HTTP协议发起远程调用
    //@FeignClient("user-service")+@GetMapping("/user/{id}")确定服务提供者的URL(http://user-service/user/{id})
    @FeignClient("user-service")
    public interface UserClient {
        //根据userId查询用户信息
        @GetMapping("/user/{id}")
        User findById(@PathVariable Long id);
    }

    这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送了。

    4.修改OrderService类

    是不是看起来优雅多了。

    //使用Feign发起远程调用
        @Autowired
        private UserClient userClient;
    
        public Order findById(Long orderId) {
            // 1.查询订单
            Order order = orderMapper.selectById(orderId);
            //2.调用user-service服务查询当前订单的用户信息
            //String url = "http://127.0.0.1:8081/user/" + order.getUserId();
            //使用RestTemplate发起远程调用
            //String url = "http://user-service/user/" + order.getUserId();
            //User user = restTemplate.getForObject(url, User.class);
            User user = userClient.findById(order.getUserId());
            //3.user封装到order对象
            order.setUser(user);
            // 4.返回
            return order;
        }

     

    三、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的日志级别可以针对单个服务:

    feign:  
      client:
        config: 
          user-service: # 针对某个微服务的配置,也可以针对所有服务,这个位置换成default
            loggerLevel: FULL #  日志级别 

    2.Java代码方式

    也可以基于Java代码来修改日志级别,在com.zhanggen.order.config包下创建类,然后声明一个Logger.Level的对象:

    package com.zhanggen.order.config;
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    
    public class FeignDefaultConfiguration  {
        @Bean
        public Logger.Level feignLogLevel(){
            return Logger.Level.FULL; // 日志级别为FULL
        }
    }

    2.1.配置局部

    如果我想让以上日志配置在调用某1个服务提供者时生效,在FeigClien接口中修改如下;

    @FeignClient(value = "user-service",configuration = FeignDefaultConfiguration.class)
    public interface UserClient {
        //根据userId查询用户信息
        @GetMapping("/user/{id}")
        User findById(@PathVariable Long id);
    }

    2.2.配置全局

    如果我想让以上日志配置在调用任意服务提供者时生效,在启动类上修改如下;

    @EnableFeignClients(defaultConfiguration = FeignDefaultConfiguration.class)
    public class OrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }

    四、Feign连接池

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

    • URLConnection:默认实现,不支持连接池,每次请求都是新建连接

    • Apache HttpClient :支持连接池

    • OKHttp:支持连接池

    因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。

    1.pom引入依赖

    <!--httpClient的依赖内置连接池 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-httpclient</artifactId>
    </dependency>

    2.application.yml配置

    max-connections-per-route:再调用某1个服务提供者时,最多从连接池中拿出50个连接发起远程调用,避免服务雪崩;

    feign:
      httpclient:
        enabled: true # 开启feign对HttpClient的支持
        max-connections: 200 # 设置最大的连接数
        max-connections-per-route: 50 # 并行接收一个服务的请求数量
        

    五、Feign公共模块

    在微服务架构中肯定会存在多个服务消费者,这些服务消费者都需要借助Feign发起远程调用;

    我们可以把Feign抽取出来作为1个公共模块以便于多个服务消费者使用;

     

     1.创建fein-api模块

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

    2.pom依赖依赖

    在fein-api模块中添加以下依赖

    <dependencies>
            <!--openfeign依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <!--mybatis-plus 实体类注解要用到-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-core</artifactId>
                <version>3.4.0</version>
            </dependency>
            <!--httpclient基于连接池的调用-->
            <dependency>
                <groupId>io.github.openfeign</groupId>
                <artifactId>feign-httpclient</artifactId>
            </dependency>
        </dependencies>

    3.服务消费者

    服务消费者依赖fei-api公共模块;

      <dependency>
          <groupId>com.zhanggen</groupId>
         <artifactId>fein-api</artifactId>
          <version>1.0-SNAPSHOT</version>
      </dependency>

     服务消费者启动类

    @EnableFeignClients(defaultConfiguration = FeignDefaultConfiguration.class,
            basePackages = "com.zhanggen.feign")
    public class OrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
        //SpringBoot启动是,在Spring容器中放入1个restTemplate对象
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate() {
            return new RestTemplate();
        }
    }

     

     

    参考

  • 相关阅读:
    从dump看硬件问题
    Pycharm----【Mac】设置默认模板
    python----装饰器(几种常见方式的使用与理解)
    【Mac】打开配置文件,添加/修改环境变量
    Airtest---UI自动化测试项目
    python----PySnooper获取打印日志
    学习类网站
    unittest----assert断言的使用
    Mac---使用tree生成目录结构
    python request 留位置7
  • 原文地址:https://www.cnblogs.com/sss4/p/16414981.html
Copyright © 2020-2023  润新知