【笔记】Feign学习笔记

前言

Feign is a Java to HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. Feign’s first goal was reducing the complexity of binding Denominator uniformly to HTTP APIs regardless of ReSTfulness.(Github

添加依赖

pom.xml
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在主启动类添加注解

  • 在主启动类上添加@EnableFeignClients启动Feign自动装配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@SpringBootApplication
@MapperScan("com.dao")
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

手动指定客户端类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com;

import com.clients.UserClients;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients(clients = UserClients.class)
@SpringBootApplication
public class FeignApiApplication {

public static void main(String[] args) {
SpringApplication.run(FeignApiApplication.class, args);
}

}

创建接口

  • 创建用于发送请求的接口
  • Feign中的注解与SpringMVC中相同

@FeignClient(""):指定请求的地址(或服务名)
@GetMapping(""):发送Get请求,并指定请求参数
@PathVariable:指定Rest风格的请求参数

src/main/java/com/clients/UserClients.java
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.clients;

import com.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("eureka-service-user")
public interface UserClients {

@GetMapping("/users/{id}")
User getUserById(@PathVariable int id);
}

通过Feign发送请求

  • 使用Feign代替RestTemplate发送请求
1
2
3
4
5
6
@Autowired
private UserClients userClients;

public void method() {
User user = userClients.getUserById(order.getUserId());
}

修改日志级别

通过配置文件

feign.client.config.default.loggerLevel:设置所有服务的日志级别

NONE:缺省值。没有日志
BASIC:基本信息。包含请求发送时间、请求结束时间、请求耗时
HEADERS:详细信息。包含请求头和响应头
FULL:完整信息。包含请求体和响应体

feign.client.config.服务名.loggerLevel:设置指定服务的日志级别

src/main/resources/application.yml
1
2
3
4
5
6
7
feign:
client:
config:
default:
loggerLevel: NONE
服务名:
loggerLevel: FULL

通过配置类

创建配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.conf;

import feign.Logger;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;

public class FeignClientConfig {

@Bean
public Logger.Level feignLogLevel() {
return Logger.Level.FULL;
}
}

在全局应用配置

  • 在主启动类上的注解添加参数
1
@EnableFeignClients(defaultConfiguration = FeignClientConfig.class)

在指定服务应用配置

  • 在FeignClient借口上的注解添加参数
1
@FeignClient(value = "eureka-service-user", configuration = FeignClientConfig.class)

性能优化

  • 将默认的不支持连接池底层实现URLConnection换成支持连接池的底层实现Apache HttpClient

引入依赖

pom.xml
1
2
3
4
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>

配置连接池

feign.httpclient.enabled:启动Feign对HttpClient的支持
feign.httpclient.max-connections:最大连接数
feign.httpclient.max-connections-per-route:每个路径的最大连接数
feign.httpclient.connection-timeout:请求超时时间
feign.httpclient.time-to-live:存活时间

src/main/resource/application.yml
1
2
3
4
5
feign:
httpclient:
enabled: true
max-connections: 200
max-connections-per-route: 50

最佳实践

  • 把Feign抽取为一个服务,当其他服务需要使用Feign客户端时,继承Feign服务,就可以直接使用

抽取模块

  1. 创建一个名为FeignAPI的模块
  2. 添加依赖
FeignAPI/pom.xml
1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 在启动类添加注解
FeignAPI/src/main/java/com/FeignApiApplication.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableFeignClients
@SpringBootApplication
public class FeignApiApplication {

public static void main(String[] args) {
SpringApplication.run(FeignApiApplication.class, args);
}

}
  1. 创建实体类
FeignAPI/src/main/java/com/pojo/User.java
1
2
3
4
5
6
7
8
9
10
11
package com.pojo;

import lombok.Data;

@Data
public class User {

private Integer id;
private String name;

}
  1. 创建Feign客户端接口
FeignAPI/src/main/java/com/clients/UserClients.java
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.clients;

import com.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "eureka-service-user")
public interface UserClients {

@GetMapping("/users/{id}")
User getUserById(@PathVariable int id);
}

使用抽取的模块

  1. 在需要利用Feign发送请求的模块中,引入FeignAPI模块作为依赖
Other/pom.xml
1
2
3
4
5
<dependency>
<groupId>com</groupId>
<artifactId>FeignAPI</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
  1. 注入对象,通过对象调用方法,发起请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.service;

import com.clients.UserClients;
import com.dao.OrderDao;
import com.pojo.Order;
import com.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@Service
public class OrderService {

@Autowired
private OrderDao orderDao;

@Autowired
private UserClients userClients;

public Order getOrderById(int id) {

Order order = orderDao.selectById(id);

User user = userClients.getUserById(order.getUserId());
order.setUser(user);

return order;
}
}

完成

参考文献

哔哩哔哩——黑马程序员