目录
- 前言
- SpringCloud Feign远程服务调用
- 一.需求
- 二.两个服务的yml配置和访问路径
- 三.使用RestTemplate远程调用(order服务内编写)
- 四.使用Feign远程调用(order服务内配置)
- 五.自定义Feign配置(order服务内配置)
- 六.Feign配置日志(oder服务内配置)
- 七.Feign调优(order服务内配置)
- 八.抽离Feign
前言
微服务分解成多个不同的服务,那么多个服务之间怎么调用呢?(想要微服务项目点赞收藏评论找我拿)
SpringCloud组件原理和面试题
SpringCloud Feign远程服务调用
一.需求
现在有两个服务,订单服务和用户服务,分别对应不同的数据库。
在 查询订单的时候,把所属的用户信息一起查出来。
二.两个服务的yml配置和访问路径
用两个不同的数据库,模拟部署在两台服务器的数据库
订单yml配置 访问路径:@GetMapping("order/{orderId}")
server:
port: 8082
spring:
datasource:
url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
application:
name: orderservice //订单服务的名称
用户yml配置 访问路径:@GetMapping("user/{id}")
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
application:
name: userservice //用户服务的名称
三.使用RestTemplate远程调用(order服务内编写)
(1) 注入RestTemplate
/**
* 因为启动类本身也是一个配置了,所以我们在启动类进行注入,你自己自定义配置类注入也行
* 创建RestTemplate并注入Spring容器
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
(2) 编写远程调用
@Autowired
private RestTemplate restTemplate;
public Order queryOrderById(Long orderId) {
// 根据订单id查询订单
Order order = orderMapper.findById(orderId);
// 利用RestTemplate发起http请求,根据用户id查询用户
// url路径 http://服务名称(上面配置了)/请求路径/参数
String url = "http://userservice/user/" + order.getUserId();
// 发送http请求,实现远程调用,现在是get请求类型
User user = restTemplate.getForObject(url, User.class);
// 封装user到Order
order.setUser(user);
// 返回值
return order;
}
(3) RestTemplate的缺点
- 参数复杂URL难以维护。
- 不符合正常接口调用的格式。
四.使用Feign远程调用(order服务内配置)
(1) 引入依赖
<!--feign客户端依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
(2) 在启动类使用注解开启Feign功能
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
}
(3) 编写远程调用(在order项目内编写)
//服务名称
@FeignClient(value = "userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
(4) 调用接口
@Autowired
private UserClient userClient;
public Order queryOrderById(Long orderId) {
// 根据订单id查询订单
Order order = orderMapper.findById(orderId);
// 用Feign远程调用
User user = userClient.findById(order.getUserId());
// 封装user到Order
order.setUser(user);
// 返回
return order;
}
(5) Feign还集成了Ribbon,所以我们不用考虑负载均衡问题
五.自定义Feign配置(order服务内配置)
类型 | 作用 | 说明 |
---|---|---|
feign.Logger.Level | 修改日志级别 | 四种不同的级别:NONE(没有任何日志)、BASIC(发起请求的开始结束时间)、HEADERS(会记录请求头请求体)、FULL(请求和响应信息) |
feign.codec.Decoder | 响应结果的解析器 | http远程调用的结果做解析,例如解析json字符串为java对象 |
feign.codec.Encoder | 请求参数编码 | 将请求参数编码,便于通过http请求发送 |
feign. Contract | 支持的注解格式 | 默认是SpringMVC的注解 |
feign. Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试 |
一般我们自定义配置的是日志
六.Feign配置日志(oder服务内配置)
(1) 配置文件配置日志
//全局配置
feign:
client:
config:
default://default全局配置,远程调用的服务的接口也会打印。
loggerLevel:FULL //日志级别
//局部配置
feign:
client:
config:
orderservice://只打印服务名为orderservice的日志。
loggerLevel:FULL //日志级别
(2) 代码方式配置日志
//第一步:注入对象
public class DefaultFeignConfiguration {
@Bean
public Logger.Level logLevel(){
//日志级别
return Logger.Level.BASIC;
}
}
//第二步:注解配置
//全局配置
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
//局部配置
@FeignClient(value = "userservice",confiquration = FeignClientConfiguration.class)
七.Feign调优(order服务内配置)
Feign底层客户端实现:
- URLConnection:默认实现,不支持连接池。
- Apache HttpClient: 支持连接池。
- OKHttp:支持连接池。
(1) 使用连接池替代默认的URL Connection(使用HttpClient支持)
①pom文件引入依赖
<!--引入HttpClient依赖-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
②yml文件进行配置
feign:
httpclient:
enabled: true # 支持HttpClient的开关
max-connections: 100 # 最大连接数
max-connections-per-route: 25 # 单个路径的最大连接数
(2) 日志级别最好是basic或none
八.抽离Feign
比如 订单、商品、库存服务都要调用用户服务,那我们都需要重复写Feign调用用户服务,这样造成了很多代码冗余,所以我们要把Feign抽离出来放在一个公共的服务里面。我们新建一个 Feign-api服务,然后谁用谁就在pom文件引入一下。
<!--在order服务引入feign的统一api-->
<dependency>
<groupId>cn.xinxin.demo</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
但是这样做会导致SpringBootApplication在扫描包时找不到定义FeignClient对象,那么怎么解决呢?
解决
方式一:指定FeignClient所在包
@EnableFeignClients(basePackages = "cn.xinxin.feign.clients")
方式二:指定FeignClient字节码
EnableFeignClients(clients = {UserClient.class})
Feign-api结构目录
Feign的pom文件
<?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-demo</artifactId>
<groupId>cn.xinxin.demo</groupId>
<version>1.0</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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
</project>