美文网首页
Spring Cloud学习day99:声明式服务调用Feign

Spring Cloud学习day99:声明式服务调用Feign

作者: 开源oo柒 | 来源:发表于2019-12-05 23:25 被阅读0次

    一、Feign的定义

    1.什么是Feign?

    Feign 是一种声明式、模板化的 HTTP 客户端(仅在 consumer 中使用)。
    Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。
    Feign被广泛应用在Spring Cloud 的解决方案中,是学习基于Spring Cloud 微服务架构不可或缺的重要组件。

    • Feign解决了什么问题:

    装了Http调用流程,更适合面向接口化的变成习惯。
    在服务调用的场景中,我们经常调用基于Http协议的服务,而我们经常使用到的框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty等等,这些框架在基于自身的专注点提供了自身特性。而从角色划分上来看,他们的职能是一致的提供Http调用服务。

    • 调用流程:

    调用方Client框架服务方构造Http请求URL填写Http请求头信息填写消息报文信息发送Http请求处理请求,返回结果返回报文提取报文信息,转换成对应的Java bean根据Bean中的定义,业务处理调用方Client框架服务方。

    2.什么是声明式?

    声明式调用就像调用本地方法一样调用远程方法;无感知远程 http 请求。

    • 声明式的作用:

    Spring Cloud 的声明式调用, 可以做到使用 HTTP 请求远程服务时能就像调用本地 方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个 HTTP 请求。
    它像 Dubbo 一样,consumer 直接调用接口方法调用 provider,而不需要通过常规的 Http Client 构造请求再解析返回数据。

    • 解决了什么问题:

    它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细 节,更无需关注分布式环境开发。


    二、Feign简单案例

    1.实现Feign的简单操作:

    需求实现对商品的基本操作。

    示例
    1.1创建Product-Service项目:

    使用Eclipse创建Maven项目。使用Eureka的集群注册中心。

    • 修改POM文件添加依赖:
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
        </dependencies>
    
    • 创建Service接口:
    /**
     * 服务的接口
     * @author zhang
     */
    @RequestMapping("/product")
    public interface ProductService {
    
        // 查询所有
        @RequestMapping(value = "/findAll", method = RequestMethod.GET)
        public List<Product> findAll();
    }
    
    • 创建实体类(getter和setter方法)
    public class Product {
        private Integer id;
        private String name;
    
        public Product() {
            super();
        }
        public Product(Integer id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    
    1.2创建Product-Provider项目:
    • 修改POM文文件添加依赖:
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>com.zlw</groupId>
                <artifactId>springcloud-feign-service</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
    • 添加全局配置文件:
    spring.application.name=product-provider
    server.port=9093
    #设置服务注册的中心地址,指向另一个注册中心
    eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/ 
    
    • 创建Controller:
    /**
     * Provider服务
     * @author zhang
     *
     */
    @RestController
    public class ProductController implements ProductService{
    
        @Override
        public List<Product> findAll() {
            List<Product> list=new ArrayList<Product>();
            list.add(new Product(1,"电脑"));
            list.add(new Product(2,"手机"));
            list.add(new Product(3,"电视"));
            
            return list;
        }
    }
    
    • 创建启动类:
    @EnableEurekaClient
    @SpringBootApplication
    public class ProductApplication {
        
        public static void main(String[] args) {
            SpringApplication.run(ProductApplication.class, args);
        }
    }
    
    1.3创建Product-Consumer:
    • 修改POM文件添加依赖:

    添加Product-Service的坐标;添加Feign的坐标。

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <!-- 添加 Feign 坐标 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
            <!-- 添加 product-service 坐标 -->
            <dependency>
                <groupId>com.zlw</groupId>
                <artifactId>springcloud-feign-service</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
    • 添加全局配置文件:
    spring.application.name=product-consumer
    server.port=9094
    
    #设置服务中心地址,指向另一个注册中心
    eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
    
    • 创建Service接口:
    @FeignClient(name = "product-provider")
    public interface ConsumerService extends ProductService{
    }
    
    • 创建Controller:
    /**
     * Consumer服务
     * 
     * @author zhang
     *
     */
    @RestController
    public class ConsumerController {
    
        @Autowired
        ConsumerService consumerService;
    
        // 查询所有
        @RequestMapping(value = "list", method = RequestMethod.GET)
        public List<Product> list() {
            List<Product> list = consumerService.findAll();
            return list;
        }
    }
    
    • 创建启动类:
    @EnableFeignClients
    @EnableDiscoveryClient
    @SpringBootApplication
    public class ConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
    Provid
    Consumer
    注册中心

    2.Feign的单个参数处理:

    基于上面的项目环境进行修改;添加在Service中添加参数传递的方法。

    • 修改Product-Service:
    // 传递单个参数
        @RequestMapping(value = "findById", method = RequestMethod.GET)
        public Product findById(@RequestParam("id") Integer id);
    
    • 修改Product-Provider:
        @Override
        public Product findById(Integer id) {
            return new Product(id,"ProductName");
        }
    
    • 修改Product-Consumer:
        // 单个参数传递
        @RequestMapping(value = "findById", method = RequestMethod.GET)
        public Product findById(@RequestParam("id") Integer id) {
            return consumerService.findById(id);
        }
    
    Consumer
    Provider

    3.Feign的多个参数传递:

    3.1基于GET的提交方式:
    • 修改Product-Service
        // 方式一:使用GET请求,传递多个参数,(传递对象必须拆分为多个单个参数)
        @RequestMapping(value = "addProduct", method = RequestMethod.GET)
        public Product addProduct(@RequestParam("id") Integer id, @RequestParam("name") String name);
    
    • 修改Product-Provider:
        @Override
        public Product addProduct(Integer id, String name) {
            return new Product(id,name);
        }
    
    • 修改Product-Consumer:
        // 多个参数传递,方式一:GET请求
        @RequestMapping(value = "add", method = RequestMethod.GET)
        public Product addProduct(Product product) {
            return consumerService.addProduct(product.getId(), product.getName());
        }
    
    示例
    3.2基于POST的提交方式:
    • 修改 Product-Service :
        //方式二:使用POST请求,传递多个参数
        @RequestMapping(value = "addProduct2",method = RequestMethod.POST)
        public Product addProduct2(@RequestBody Product product);
    
    • 修改 Product-Provider:
        @Override
        public Product addProduct2(@RequestBody Product product) {
            return product;
        }
    
    • 修改 Product-Consumer :
        //方式二:POST请求,多参数传递
        @RequestMapping(value = "add2",method = RequestMethod.GET)
        public Product add(Product product) {
            return consumerService.addProduct2(product);
    
    示例

    三、Feign操作案例使用MyBatis操作数据库

    实现对数据库的增查操作,演示Feign中的不同参数传递。
    使用Eclipse创建项目搭建环境。

    示例
    • 数据库:
    CREATE TABLE `users` (
      `userid` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(30) DEFAULT NULL,
      `userage` int(5) DEFAULT NULL,
      PRIMARY KEY (`userid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
    

    1.创建MyBatis-Service项目:

    • 修改POM文件添加相关依赖:
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    • 创建接口:
    @FeignClient(name = "users-provider")
    public interface UserServiceFeign {
    
        @RequestMapping("/user")
        public List<User> findAll();
    
        @RequestMapping("/user/{userid}")
        public User findById(@PathVariable("userid") int userid);
    
        @RequestMapping("/findOne")
        public User findOne(@RequestParam("userid") int userid);
    
        @RequestMapping(value = "/add", method = RequestMethod.POST)
        public int addUser(@RequestBody User user);
    }
    
    • 创建实体类(get和set):
        private int userid;
        private String username;
        private int userage;
    
    

    2.创建MyBatis-Provider:

    • 修改POM文件,添加相关依赖:
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <!-- Mybatis 启动器 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.1.1</version>
            </dependency>
            <!-- mysql 数据库驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!-- druid 数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.9</version>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
            <!--配置资源拷贝插件 -->
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.yml</include>
                        <include>**/*.properties</include>
                    </includes>
                </resource>
            </resources>
        </build>
    
    • 修改全局配置文件:
    spring.application.name=user-provider
    #配置端口
    server.port=9096
    
    #mybatis
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/ssm
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    mybatis.type-aliases-package=com.zlw.pojo
    
    #配置eureka信息
    eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/ 
    
    • 创建实体类:
        private int userid;
        private String username;
        private int userage;
    
    • 创建mapper接口和映射文件:
    public interface UserMapper {
    
        public List<User> findAll();
    
        public User findById(int userid);
    
        public int AddUser(User user);
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.zlw.mapper.UserMapper">
        <select id="findAll" resultType="user">
            select * from users
        </select>
        <select id="findById" resultType="user">
            select *from users where userid=#{userid}
        </select>
        <insert id="addUser" parameterType="user">
            insert into users(username,userage) values(#{username},#{userage})
        </insert>
      </mapper>
    
    • 创建Service接口和实现类:
    public interface UserService {
    
        // 查询所有
        public List<User> findAll();
    
        // 查询指定
        public User findById(int userid);
    
        // 添加
        public int addUser(User user);
    }
    
    @Service
    public class UserServiceImpl implements UserService {
        
        @Autowired
        UserMapper userMapper;
    
        @Override
        public List<User> findAll() {
            return userMapper.findAll();
        }
    
        @Override
        public User findById(int userid) {
            return userMapper.findById(userid);
        }
    
        @Override
        public int addUser(User user) {
            return userMapper.AddUser(user);
        }
    }
    
    • 创建Controller:
    @RestController
    public class UserController {
    
        @Autowired
        UserService userService;
    
        // 查询所有
        @RequestMapping("/user")
        public List<User> findAll() {
            List<User> list = userService.findAll();
            return list;
        }
    
        // 查询指定
        @RequestMapping("/user/{userid}")
        public User findById(@PathVariable int userid) {
            User user = userService.findById(userid);
            return user;
        }
    
        // 添加
        @RequestMapping(value = "/add", method = RequestMethod.POST)
        public int add(User user) {
            int num = userService.addUser(user);
            return num;
        }
    }
    
    • 创建启动类:
    @EnableEurekaClient
    @MapperScan({"com.zlw.mapper"})
    @SpringBootApplication
    public class ProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ProviderApplication.class, args);
        }
    }
    

    3.创建MyBatis-Consumer:

    • 修改POM文件,添加相关依赖:
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR5</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
            <dependency>
                <groupId>com.zlw</groupId>
                <artifactId>springcloud-feign-mybits-service</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
        </dependencies>
    
    • 修改配置文件:
    spring.application.name=user-consumer
    server.port=9097
    
    eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
    
    • 创建Controller:
    @RestController
    public class UserController {
    
        @Autowired
        UserServiceFeign userService;
        
        @RequestMapping("/user")
        public List<User> findAll() {
            return userService.findAll();
        }
        
        @RequestMapping("/user/{userid}")
        public User findById(@PathVariable int userid) {
            return userService.findById(userid);        
        }
        
        @RequestMapping("/findOne")
        public User findOne(int userid) {
            return userService.findOne(userid);
        }
        
        @RequestMapping("/addUser")
        public int addUser(User user) {
            return userService.addUser(user);
        }
    }
    
    • 页面跳转:
    @Controller
    public class PageShow {
        
        @RequestMapping("/{page}")
        public String show(@PathVariable String page) {
            return page;
        }
    }
    
    • 在templates目录下创建addUser.html:
    <html xmlns:th="www.thymeleaf.org">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    </head>
    <body>
        <form th:action="@{/addUser}" method="post">
            <p>
                用户名:<input type="text" name="username" />
            </p>
            <p>
                年龄:<input type="text" name="userage" />
            </p>
            <p>
                <input type="submit" value="添加" />
            </p>
        </form>
    </body>
    </html>
    
    • 创建启动类:
    @EnableFeignClients(basePackages = "com.zlw.service")
    @EnableDiscoveryClient
    @SpringBootApplication
    public class ConsumerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
    查询所有
    单个参数

    四、Feign的性能优化

    1.使用Gzip压缩算法:

    • 什么是gzip?

    gzip 是一种数据格式,采用用 deflate 算法压缩 data;gzip 是一种流行的文件 压缩算法,应用十分广泛,尤其是在 Linux 平台。
    当 Gzip 压缩到一个纯文本文件时,效果是非常明显的,大约可以减少 70%以上的文件大小。

    • gzip的作用:

    网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可 以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏 览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的系。例如 Google 就可以通过直接读取 gzip 文件来比普通手工抓取 更快地检索网页。

    • HTTP协议中对压缩传输的规定:

    (1)客户端向服务器请求中带有:Accept-Encoding:gzip, deflate 字段,向服务器表示, 客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务器是不会压缩的。
    (2)服务端在收到请求之后,如果发现请求头中含有 Accept-Encoding 字段,并且支 持该类型的压缩,就对响应报文压缩之后返回给客户端,并且携带 Content-Encoding:gzip 消 息头,表示响应报文是根据该格式压缩过的。
    (3)客户端接收到请求之后,先判断是否有 Content-Encoding 消息头,如果有,按该 格式解压报文。否则按正常报文处理。

    示例

    2.测试支持Gzip压缩的案例:

    使用Feign简单案例中的测试环境,创建新的Product-Consumer项目。

    2.1通过 Feign 到 Provider 的请求与相应的 Gzip 压缩:
    • 修改Consumer的配置文件:
    spring.application.name=product-consumer
    server.port=9095
    
    eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
    
    #-----------------------------feign gzip 
    #配置请求 GZIP 压缩 
    feign.compression.request.enabled=true
    #配置响应 GZIP 压缩 
    feign.compression.response.enabled=true
    #配置压缩支持的 MIME TYPE 
    feign.compression.request.mime-types=text/xml,application/xml,application/json 
    #配置压缩数据大小的最小阀值,默认 2048 
    feign.compression.request.min-request-size=512
    
    示例
    2.2对客户端浏览器的请求以及 Consumer 对 provider 的请求与响应做 Gzip 压缩:
    • 修改Consumer的配置文件:
    #-----------------------------spring boot gzip 
    #是否启用压缩  
    server.compression.enabled=true
    server.compression.mime-types=application/json,application/ xml,text/html,text/xml,text/plain
    
    示例
    示例

    3.使用Http连接池:

    • Http的背景原理:

    (1)两台服务器建立 http 连接的过程是很复杂的一个过程,涉及到多个数据包的交换,并 且也很耗时间。
    (2)Http 连接需要的 3 次握手 4 次分手开销很大,这一开销对于大量的比较小的 http 消 息来说更大。

    • 优化性能的解决方案:

    (1)如果我们直接采用 http 连接池,节约了大量的 3 次握手 4 次分手;这样能大大提升吞 吐率。
    (2)feign的http 客户端支持3种框架;HttpURLConnection、httpclient、okhttp;默认是 HttpURLConnection。
    (3)传统的 HttpURLConnection 是 JDK 自带的,并不支持连接池,如果要实现连接池的 机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,如果有可用的 其他方案,也没有必要自己去管理连接对象。
    (4)HttpClient 相比传统 JDK 自带的 HttpURLConnection,它封装了访问 http 的请求头, 参数,内容体,响应等等;它不仅使客户端发送 HTTP 请求变得容易,而且也方便了开发人 员测试接口(基于 Http 协议的),即提高了开发的效率,也方便提高代码的健壮性;另外 高并发大量的请求网络的时候,还是用“连接池”提升吞吐量。

    4.1使用HttpClient客户端工具:

    使用Feign简单案例中的测试环境,创建新的Product-Consumer项目。

    • 修改POM配置文件添加HTTPClient的坐标:
            <!-- 使用Apache HttpClient替换Feign原生httpURLConnection -->
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
            </dependency>
            <dependency>
                <groupId>com.netflix.feign</groupId>
                <artifactId>feign-httpclient</artifactId>
                <version>8.17.0</version>
            </dependency>
    
    • 修改配置文件开启HttpClient的使用:
    spring.application.name=product-consumer
    server.port=9098
    
    eureka.client.serviceUrl.defaultZone=http://admin:123456@eureka1:8761/eureka/,http://admin:123456@eureka2:8761/eureka/
    #启用 httpclient 
    feign.httpclient.enabled=true 
    
    • 注意:

    如果使用 HttpClient 作为 Feign 的客户端工具。那么在定义接口上的注解是需要 注意,如果传递的是一个自定义的对象(对象会使用 json 格式来专递)。需要制定类型。

    • 修改Product-Service:
        // 添加商品传递多个参数 方式二 :POST 方式
         @RequestMapping(value="/add2",method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE) 
         public ProductaddProduct2(@RequestBody Product product); 
         //使用 HttpClient 工具 添加商品传递多个参数 :基于GET 方式 
         @RequestMapping(value="/add3",method=RequestMethod.GET,consumes=MediaType.APPLICATION_JSON_VALUE) 
         public Product addProduct3(Productproduct); 
    

    4.查看微服务日志中记录每个接口 URL,状态码和耗时信息 :

    • 日志的级别:
    级别 说明
    NONE 不做任何记录
    BASIC 只记录输出Http 方法名称、请求URL、返回状态码和执行时间
    HEADERS 记录输出Http 方法名称、请求URL、返回状态码和执行时间 和 Header 信息
    FULL 记录Request 和Response的Header,Body和一些请求元数据
    • 创建Consumer:

    使用Feign简单案例中的环境。创建Consumer项目。

    • 添加logback.xml配置文件:
    <?xml version="1.0" encoding="UTF-8" ?>
     <configuration>
    <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->  
        <property name="LOG_HOME" value="${catalina.base}/logs/" />  
        <!-- 控制台输出 -->   
        <appender name="Stdout" class="ch.qos.logback.core.ConsoleAppender">
           <!-- 日志输出编码 -->  
            <layout class="ch.qos.logback.classic.PatternLayout">   
                 <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
                </pattern>   
            </layout>   
        </appender>   
        <!-- 按照每天生成日志文件 -->   
        <appender name="RollingFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--日志文件输出的文件名-->
                <FileNamePattern>${LOG_HOME}/server.%d{yyyy-MM-dd}.log</FileNamePattern>   
                <MaxHistory>30</MaxHistory>
            </rollingPolicy>   
            <layout class="ch.qos.logback.classic.PatternLayout">  
                <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
                </pattern>   
           </layout> 
            <!--日志文件最大的大小-->
           <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
             <MaxFileSize>10MB</MaxFileSize>
           </triggeringPolicy>
        </appender>     
    
        <!-- 日志输出级别 -->
        <root level="DEBUG">   
            <appender-ref ref="Stdout" />   
            <appender-ref ref="RollingFile" />   
        </root> 
    
    <!--日志异步到数据库 -->  
    <!--     <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
            日志异步到数据库 
            <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
               连接池 
               <dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">
                  <driverClass>com.mysql.jdbc.Driver</driverClass>
                  <url>jdbc:mysql://127.0.0.1:3306/databaseName</url>
                  <user>root</user>
                  <password>root</password>
                </dataSource>
            </connectionSource>
      </appender> -->
    </configuration>
    
    • 在启动类中添加方法:
    // NONE:不记录任何信息,默认值 
    // BASIC:记录请求方法、请求 URL、状态码和用时
    // HEADERS:在 BASIC 基础上再记录一些常用信息 
    // FULL:记录请求和相应的所有信息 
        @Bean
        public Logger.Level getLog(){
            return Logger.Level.FULL;
        }
    

    5.配置Feign负载均衡请求超时时间:

    Feign 的负载均衡底层用的就是 Ribbon。

    5.1修改Consumer中的配置文件:
    • 全局配置:
    #全局配置 
    # 请求连接的超时时间 默认的时间为 1 秒 ribbon.ConnectTimeout=5000 
    # 请求处理的超时时间 
    ribbon.ReadTimeout=5000 
    
    • 局部配置:
    #局部配置 
    # 对所有操作请求都进行重试 
    ego-product-provider.ribbon.OkToRetryOnAllOperations=true 
    # 对当前实例的重试次数 
    ego-product-provider.ribbon.MaxAutoRetries=2 
    # 切换实例的重试次数 
    ego-product-providert.ribbon.MaxAutoRetriesNextServer=0 
    # 请求连接的超时时间 
    ego-product-provider.ribbon.ConnectTimeout=3000 
    # 请求处理的超时时间 
    ego-product-provider.ribbon.ReadTimeout=3000 
    

    相关文章

      网友评论

          本文标题:Spring Cloud学习day99:声明式服务调用Feign

          本文链接:https://www.haomeiwen.com/subject/wlijgctx.html