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

一、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 
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容