Feign组件
Feign使用方式
使用动态代理技术,生成接口的代理类对象,在代理类对象中完成远程调用. 封装了如下代码: 硬编码 String url = "http://userservice/user/findById/"+order.getUserId(); TbUser user = restTemplate.getForObject(url, TbUser.class);
1.导入feign的启动器
<!-- Feign启动器 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
2.开启Feign客户端支持
在服务消费者引导类中添加注解 @EnableFeignClients
3.编写feign客户端接口
客户端接口要与服务提供者的入口方法保持一致(与服务提供者Controller中的方法名一致)
@FeignClient("userservice") // 设置服务提供者的名称
@Component // 创建接口实现类对象,并将对象存放到IOC容器中
/**
* @Author: huahua
* @name:UserFeignClient
* @Date:2023/8/15 14:38
* todo: Feign原理: 使用动态代理技术生成当前接口的代理类,在代理类中使用RestTemplate进行远程访问
*/
@FeignClient(value = "userservice",path = "/user")
@Component // 创建当前接口的代理类对象,并将对象存放到IOC容器中
public interface UserFeignClient {
// 直接从被调用的服务中(controller层)抄过来即可
@RequestMapping("/findById/{id}")
TbUser findById(@PathVariable Integer id);
}
4.调用Feign客户端实现远程调用
/**
* @author 85190
* @description 针对表【tb_order】的数据库操作Service实现
* @createDate 2023-08-14 18:45:59
*/
@Service
public class TbOrderServiceImpl extends ServiceImpl<TbOrderMapper, TbOrder>
implements TbOrderService{
// @Autowired
// private RestTemplate restTemplate;
@Autowired
private UserFeignClient userFeignClient;
@Override
public TbOrder findById(Integer id) {
// todo:根据ID查询订单信息
TbOrder order = this.getById(id);
// todo: 远程访问user服务,根据ID查询用户信息
TbUser user = userFeignClient.findById(Integer.parseInt(order.getUserId()+""));
// todo: 封装结果
order.setUser(user);
return order;
}
// @Override
// public TbOrder findById(Integer id) {
// // todo:根据ID查询订单信息
// TbOrder order = this.getById(id);
// // todo: 远程访问user服务,根据ID查询用户信息
// //String url = "http://localhost:8081/user/findById/"+order.getUserId();
// String url = "http://userservice/user/findById/"+order.getUserId();
// //String forObject = restTemplate.getForObject(url, String.class);
// TbUser user = restTemplate.getForObject(url, TbUser.class);
// // todo: 封装结果
// order.setUser(user);
// return order;
// }
}
Hystix支持(了解)
1.开启Feign内部Hystrix支持
feign:
hystrix:
enabled: true # 开启Feign的熔断功能
2.编写降级类,提供降级方法
/**
* @Author: huahua
* @name:UserFeignClientHystrix
* @Date:2023/8/15 15:06
*/
@Component
public class UserFeignClientHystrix implements UserFeignClient{
@Override
public TbUser findById(Integer id) {
TbUser user = new TbUser();
user.setUsername("Feign降级了...");
return user;
}
}
3.在Feign客户端类上指定降级类
/**
* @Author: huahua
* @name:UserFeignClient
* @Date:2023/8/15 14:38
* todo: Feign原理: 使用动态代理技术生成当前接口的代理类,在代理类中使用RestTemplate进行远程访问
*/
@FeignClient(value = "userservice",path = "/user",fallback = UserFeignClientHystrix.class)
@Component // 创建当前接口的代理类对象,并将对象存放到IOC容器中
public interface UserFeignClient {
@RequestMapping("/findById/{id}")
TbUser findById(@PathVariable Integer id);
}
日志级别
记录服务调用时生成的日志信息
1.配置日志包
logging:
level:
com.huahua: debug
2.编写配置类,定义日志级
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
这里指定的Level级别是FULL,Feign支持4种级别:
-
NONE:不记录任何日志信息,这是默认值。
-
BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
-
HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
-
FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
3.Feign客户端开启日志记录
/**
* 作用: user-service服务客户端接口
* feign会生成当前接口的代理类对象,
* 在代理类对象中完成对user-service的远程调用
*/
@FeignClient(
value = "user-service",
fallback = UserServiceFeignHystrix.class,
configuration = FeignConfig.class
)
@Component
public interface UserServiceFeignClient {
@RequestMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
Feign负载均衡
ribbon:
ConnectTimeout: 500 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
MaxAutoRetries: 3 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 1 # 重试多少个实例
OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
# 修改ribbon获取服务地址的加载策略: 饥饿加载(默认为懒加载)
eager-load:
enabled: true
clients: user-service
Feign-API抽取
创建一个feign-api模块
导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud-parent</artifactId>
<groupId>com.bw.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>feign-api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- Feign启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>
提供相关的Feign接口
/**
* @Author: huahua
* @name:UserFeignClient
* @Date:2023/8/15 14:38
* todo: Feign原理: 使用动态代理技术生成当前接口的代理类,在代理类中使用RestTemplate进行远程访问
*/
@FeignClient(value = "userservice",
path = "/user",
fallback = UserFeignClientHystrix.class,
configuration = FeignConfig.class)
@Component // 创建当前接口的代理类对象,并将对象存放到IOC容器中
public interface UserFeignClient {
@RequestMapping("/findById/{id}")
TbUser findById(@PathVariable Integer id);
}
提供相关的降级方法
/**
* @Author: huahua
* @name:UserFeignClientHystrix
* @Date:2023/8/15 15:06
*/
@Component
public class UserFeignClientHystrix implements UserFeignClient {
@Override
public TbUser findById(Integer id) {
TbUser user = new TbUser();
user.setUsername("Feign降级了...");
return user;
}
}
配置Feign的日志级别
// 声明配置类
@Configuration
public class FeignConfig {
@Bean // 将方法的返回值存放到IOC容器中
Logger.Level feignLoggerLevel(){
//- NONE:不记录任何日志信息,这是默认值。
//- BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
//- HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
//- FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
return Logger.Level.FULL;
}
}
在需要使用的服务中导入
<dependency>
<groupId>com.huahua.cloud</groupId>
<artifactId>feign-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;
/**
* @Author: hauhua
* @name:OrderApp
* @Date:2023/8/14 18:47
*/
// 当不声明需要扫描的包时,扫描将从引导类所在的包开始扫描
@SpringBootApplication
@MapperScan("com.bw.order.mapper")
@EnableHystrix
// 声明Feign接口所在的位置 UserFeignClient
@EnableFeignClients(basePackages = "com.bw.feign")
// 配置SpringBoot需要扫描的包(一旦设置了扫描的包,那么SpringBoot默认的扫包机制将不再生效)
@ComponentScan({"com.bw.feign","com.bw.order"})
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class,args);
}
}
Feign优化
OpenFeign
--> RestTemplate(Spring)
--> URLConnection|Apache HttpClient|OKHttp
--> 对网络编程的客户端进行的封装
Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:
•URLConnection:默认实现,不支持连接池
•Apache HttpClient :支持连接池
•OKHttp:支持连接池
因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。
这里我们用Apache的HttpClient来演示。
1)引入依赖
在order-service的pom文件中引入Apache的HttpClient依赖:
<!--httpClient的依赖 --> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>
2)配置连接池
在order-service的application.yml中添加配置:
feign: client: config: default: # default全局的配置 loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息 httpclient: enabled: true # 开启feign对HttpClient的支持 max-connections: 200 # 最大的连接数 max-connections-per-route: 50 # 每个路径的最大连接数