http client Feign
- Feign replaces RestTemplate
- custom configuration
- Feign usage optimization
- Best Practices
Problems with calling RestTemplate
The code that used to initiate remote calls using RestTemplate:
String url = "http://userservice/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
There are following problems:
- Poor code readability and inconsistent programming experience
- URLs with complex parameters are difficult to maintain
Feign's introduction
Feign is a declarative http client, official address: http://github.com/OpenFeign/feign
Its role is to help us send http requests elegantly and solve the problems mentioned above.
Define and use Feign client
The steps to use Feign are as follows:
1. Introduce dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. Enable the function of Feign in the Tainan Jia annotation of the order-service startup class
@EnableFeignClients
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
The steps to use Feign are as follows:
3. Write Feign client
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
It is mainly based on SpringMVC annotations to declare remote call information, such as:
- Service name: userservice
- Request method: GET
- Request path: /user/{id}
- Request parameter: Long id
- Return value type: User
4. Use Feign client instead of RestTemplate
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findByid(orderId);
// 2.利用Feign发起http请求,查询用户
User user = userClient.findById(order.getUserId());
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
summary:
Steps to use Feign:
- Introduce dependencies
- Add @EnableFeignClients annotation
- Write the FeignClient interface
- Use methods defined in FeignClient instead of RestTemplate
Feign - custom configuration
Customize the configuration of Feign
Feign runs a custom configuration to override the default configuration. The configuration that can be modified is as follows:
type | effect | illustrate |
---|---|---|
feign.Logger.Level | Modify log level | Contains four different levels: NONE, BASIC, HEADERS, FULL |
feign.codec.Decoder | Parser for the response result | Parsing the results of http remote calls, such as parsing json strings into java objects |
feign.codec.Encoder | request parameter encoding | Encode request parameters for sending via http requests |
feign.Contract | Supported Annotation Formats | The default is the annotation of the MVC of S weekdays |
feign.Retryer | Failure retry mechanism | The retry mechanism for request failure, the default is no, but Ribbon's retry will be used |
Generally, what we need to configure is the log level.
There are two ways to configure Feign logs:
Method 1: configuration file method
- Take effect globally:
feign:
client:
config:
default: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
- partial effect
feign:
client:
config:
userservice: #这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
The second method of configuring Feign logs: java code method, you need to declare a Bean first:
public class FeignClientConfiguration {
@Bean
public Logger.Level feignLogLevel() {
return Logger.Level.BASIC;
}
}
- If it is a global configuration, put it in the @EnableFeignClients annotation:
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
- If it is a partial configuration, put it in the @FeignClient annotation:
@FeignClients(value="userservice", configuration = FeignClientConfiguration.class)
summary:
Feign's log configuration:
1. The first method is the configuration file, feign.client.config.xxx.loggerLevel
- If xxx is default, it means global
- If xxx is the service name, such as userservice, it represents the service
2. The second method is to configure the Logger.level Bean in java code
- If declared in the @EnableFeignClients annotation, it represents the global
- If declared in the @FeignClient annotation, it represents a service
Feign-performance optimization
Feign performance optimization
The underlying client implementation of Feign:
- URLConnection: default implementation, does not support connection pooling
- Apache HttpClient: supports connection pooling
- OKHttp: support connection pool
Therefore, optimizing the performance of Feign mainly includes:
- Use a connection pool instead of the default URLConnection
- log level, preferably basic or none
Feign performance optimization - connection pool configuration
Feign adds HttpClient support:
import dependencies:
<!--httpClient的依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
Configure the connection pool:
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对httpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径最大的连接数
summary:
Feign's optimization:
1. Try to use basic as the log level
2. Use HttpClient or OKHttp instead of URLConnection
- Introduce feign-httpClient dependency
- The configuration file enables the httpClient function and sets the connection pool parameters
Feign - Best Practice Analysis
Best Practices for Feign
Method 1 (inheritance): Define a unified parent interface for the consumer's FeignClient and the provider's controller as a standard.
- Services Tightly Coupled
- Mappings in parent interface parameter lists are not inherited
public interface UserAPI {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
@FeignClient(value = "userservice")
public interface UserClient extends UserAPI{
}
@RestController
public class UserController implements UserAPI{
public User findById(@PathVariable("id") Long id){
// ...实现业务
}
}
Method 2 (extraction): Extract FeignClient as an independent module, and put the POJO related to the interface and the default Feign configuration into this module, and provide it to all consumers
summary:
Best practices for Feign:
- Let controller and FeignClient inherit the same interface
- Define the default configuration of FeignClient, POJO, and Feign into one project for all consumers to use
Feign - Implementing Feign best practices
Extract FeignClient
The steps to implement Best Practice Method 2 are as follows:
1. First create a module named feign-api, and then import feign's starter dependency
2. Copy the UserClient, User, and Default FeignConfiguration written in order-service to the feign-api project
3. Introduce feign in order-service -api depends on
4. Modify all the import parts related to the above three components in order-service, and change it to import the package in feign-api
5. Restart the test
When the defined FeignClient is not within the scanning range of SpringBootApplication, these FeignClient cannot be used. There are two ways to solve it:
Method 1: Specify the package where FeignClient is located
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
Method 2: Specify FeignClient bytecode
@EnableFeignClients(clients= {
UserClient.class})
summary:
There are two ways to import FeignClient of different packages:
- Add basePackages in the @EnableFeignClients annotation to specify the package where FeignClient is located
- Add clients to the @EnableFeignClients annotation to specify the bytecode of the specific FeignClient