目录
3:openfeign案例使用,访问localhost:8080/
3.2:客户端定义相同的controller接口方法使用FeignClient注解
7.2:8080效果检查(实际上没成功,数据量是44974)
1:什么是openfeign
封装了http协议,调用方式改成面向接口。在服务中我们有了consul的服务发现和服务注册,那么怎么调用服务呢?在上一章中,我们会用了Robbin的http的restTemplate调用。但是程序员喜欢面向接口的编程,调用别人的controller方法要是能够像调用本地方法一样,那该多好呢。所以openfeign来了。这是重点
2:openfeign的作用
就是封装http,远程调用controller跟调用本地方法一样。
3:openfeign案例使用,访问localhost:8080/
3.1:pom配置,引入openfeign包
<!--
本项目采用jdk17
springboot 3.2.7
spring-cloud 2023.0.3(最新版本支持springBoot 3.3.x, 3.2.x)
https://docs.spring.io/spring-cloud-release/reference/index.html
-->
<properties>
<java.version>17</java.version>
<spring-cloud.version>2023.0.3</spring-cloud.version>
</properties>
<dependencies>
<!--导入公共依赖包-->
<dependency>
<groupId>org.example</groupId>
<artifactId>CloudAPI_Commoms</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--springboot的健康监控,springCloud依赖这个监控,来发送心跳-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--
swagger3的springboot依赖
Springdoc OpenAPI 1.x:支持 JDK 8 及以上版本(Spring Boot 2.x and 1.x.)
Springdoc OpenAPI 2.x:最新版本要求 JDK 11 及以上(Spring Boot 3.x)
访问地址:
http://localhost:8091/swagger-ui/index.html
-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.5.0</version>
</dependency>
<!--
1:导入consul的依赖 consul版本是4.1.2
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--openfeign调用依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<!--spring-cloud-dependencies 版本控制,就不用写不同的组件版本了 很方便-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.2:客户端定义相同的controller接口方法使用FeignClient注解
方法名字一样,使用FeignClient注解
//PayController接口的方法和服务端方法名字一样
@FeignClient(value = "PayService") //value的名字是consul中注册的服务名字
public interface PayFeignApi {
//实际地址就是
// PayService/pay/add 对应的就是8091 8082的/pay/add方法
@PostMapping(value = "/pay/add")
ResultData<Object> add(@RequestBody TPay tPay);
@DeleteMapping(value = "/pay/delete/{id}")
ResultData<Object> delete(@PathVariable Integer id);
@PutMapping(value = "/pay/update")
ResultData<Object> update(@RequestBody TPayDTO payDTO);
@GetMapping(value = "/pay/get/{id}")
ResultData<Object> getById(@PathVariable("id") Integer id);
@GetMapping(value = "/pay/getALL")
ResultData<Object> getAll();
/**
* 自定义异常捕获,不使用全局异常
*
* @return
*/
@GetMapping(value = "/pay/error")
ResultData<Object> error();
@GetMapping(value = "/pay/info")
String consul_info(@Value("${student.info}") String info);
}
3.2:客户端controller的方法
注入接口,跟调用本地方法似的
/**
* 通过RestTemplate
* 订单服务Controller的服务8080 ---> 调用远程的8091的支付服务
*/
@RestController
public class OrderControllerFeign {
@Autowired
PayFeignApi payFeignApi;
//这里自动负载均衡到91 92两台服务器上
@GetMapping(value = "/consumer/pay/get/{id}")
public ResultData<Object> get(@PathVariable(value = "id") Integer id) {
System.out.println("===feign调用/consumer/pay/get/{id}===");
//地址是: PayService/pay/get/{id}
return payFeignApi.getById(id);
}
/**
* 订单服务创建订单
*/
@PostMapping(value = "/consumer/pay/add")
public ResultData addOrder(@RequestBody TPay tPay) {
System.out.println("===feign调用/consumer/pay/add===");
ResultData<Object> resultData= payFeignApi.add(tPay);
return resultData;
}
@GetMapping(value = "/consumer/pay/getALL")
public ResultData<Object> getAll() {
ResultData<Object> resultData= payFeignApi.getAll();
return resultData;
}
@DeleteMapping(value = "/consumer/pay/delete/{id}")
public ResultData delete(@PathVariable Integer id) {
ResultData<Object> resultData= payFeignApi.delete(id);
return resultData;
}
/**
* 修改数据
*
* @param payDTO
* @return
*/
@PutMapping(value = "/consumer/pay/update")
public ResultData<Object> update(@RequestBody TPayDTO payDTO) {
ResultData<Object> resultData= payFeignApi.update(payDTO);
return resultData;
}
/**
* 获取服务集群的consul的通用配置yml
* @return
*/
@GetMapping(value = "/consumer/pay/get/info")
public String getInfo() {
return null;
}
//负载均衡原理展示
//这就是8080获取到在consul中的PayService的微服务客户端,一样两个 8091、8092
@Autowired
DiscoveryClient discoveryClient;
@GetMapping(value = "/consumer/pay/get/url")
public ResultData<Object> serviceUrl() {
List<String> services = discoveryClient.getServices();
for (String service : services) {
System.out.println("consul中的服务:"+service);
}
System.out.println("==============");
List<ServiceInstance> list = discoveryClient.getInstances("PayService");//服务名字
for (ServiceInstance instance : list) {
URI uri = instance.getUri();
System.out.println("PayService的URl:" + uri.toString());
//URl:http://192.168.31.158:8091
//URl:http://192.168.31.158:8092
}
return ResultData.success(list);
}
}
3.3启动类使用@EnableFeignClients注解
@SpringBootApplication
@EnableFeignClients(basePackages = "org.example.cloudapi_commoms.Apis") //开启feign客户端注解,第三方jar
@EnableDiscoveryClient //开启服务发现
public class Consumer2OpenFeignApplication8080 {
public static void main(String[] args) {
SpringApplication.run(Consumer2OpenFeignApplication8080.class, args);
}
}
4:openfeign调用超时
4.1: 系统默认超时时间默认60秒
代码测试8080通过openFeign调用consul上的8091服务,8091睡眠62秒,查看8080的时间
8080服务调用8091代码
//这里自动负载均衡到91 92两台服务器上
@GetMapping(value = "/consumer/pay/get/{id}")
public ResultData<Object> get(@PathVariable(value = "id") Integer id) {
System.out.println("===feign调用/consumer/pay/get/{id}===");
//地址是: PayService/pay/get/{id}
ResultData<Object> resultData ;
try {
System.out.println("openFeign根据id查询数据开始:"+ DateUtil.now());
resultData= payFeignApi.getById(id);//8080调用8091
} catch (Exception e) {
System.out.println("openFeign根据id查询数据结束:"+ DateUtil.now());
throw new RuntimeException(e);
}
return resultData;
}
8091服务睡觉62秒
@GetMapping(value = "/pay/get/{id}")
@Operation(summary = "根据id查询", description = "参数是id")
public ResultData<Object> getById(@PathVariable("id") Integer id) {
TPay byId = tPayService.getById(id);
if (id == -1) {
throw new RuntimeException("id不能为负数");
}
try {
System.out.println("8091服务休眠62秒,测试openFeign的超时时间");
TimeUnit.SECONDS.sleep(61);
} catch (InterruptedException e) {
System.out.println("8091服务休眠62秒,测试openFeign的超时时间异常:"+e);
throw new RuntimeException(e);
}
if (byId == null) {
return ResultData.fail(ReturnCodeEnum.RC999.getCode(), "根据id查询数据不存在!");
}else {
return ResultData.success(byId);
}
}
8080结果测试输出时间:报错 Read timed out executing GET http://PayService/pay/get/1
4.2:自定义超时时间设置
由于系统的超时时间太长了60秒,在项目中通过8080的openfeign调用的sonsul的时候可以缩短超时间。
设置如下:分为默认时间和指定的服务超时时间
server:
port: 8080
#springcloud的consul配置 openFeign调用
spring:
application:
name: Consumer2_OpenFeign #也就是8080服务consul控制台的服务名字
cloud:
openfeign:
client:
config:
default: #default全局配置
connect-timeout: 3000 #连接时间
read-timeout: 3000 #默认60秒 也就是读取超时,调用其他服务的超时时间
PayService: #PayService的话就是指定服务91、92的时间(优先级高)
connect-timeout: 3000 #连接时间
read-timeout: 5000 #默认60秒 也就是读取超时,调用其他服务的超时时间
consul:
port: 8500
host: localhost
discovery:
service-name: ${spring.application.name}
prefer-ip-address: true #优先使用ip注册
5:超时重试
5.1:默认不会重试
5.2:自定义重试时间
8080的重试代码
@Configuration
//@Import({PayFeignApi.class})
//公共类抽取,需要把异常controller导入bean
@Import(GlobalExceptionHandler.class)
public class FeignConfig {
@Bean
public Retryer retryer(){
//return Retryer.NEVER_RETRY;
// 自定义重试 在1秒的时间内 间隔100毫秒 最大重试3次
//重试机制很危险 尽量不要设置
//假如80新增数据 调用91、92的时候,91服务超时,81重试会调用到92,92成功插入数据
//但是91也可能插入数据成功,数据就会有两条很危险
return new Retryer.Default(100,1,3);
}
}
重点:重试是危险的, 假如80新增数据调用91、92的时候,91服务超时,81重试会调用到92服务。92成功插入数据,但是91也可能插入数据成功,数据就会有两条很危险
6:openFeign性能优化httpclient5
httpclient5的有点如下:https://zhuanlan.zhihu.com/p/674084672
openFeign默认使用HttpURLConnection
从Spring Cloud OpenFeign 4开始,不再支持Feign Apache HttpClient 4。我们建议改用Apache HttpClient 5。使用HttpClient 5能提高调用性能
1:导入jar
<!--openfeign调用依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--优化openfeign的httpclient5调用 引入两个依赖 不需要指定版本 指定springCloud的版本就行 有依赖 -->
<!--优化openfeign的httpclient5调用 引入两个依赖 不需要指定版本 指定springCloud的版本就行 有依赖 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3</version>
<!-- 默认版本是5.2.3 -->
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-hc5</artifactId>
<version>13.1</version>
<!-- 默认版本是13.3 只有13.1版本支持压缩-->
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2:开启配置生效
server:
port: 8080
#springcloud的consul配置 openFeign调用
spring:
application:
name: Consumer2_OpenFeign #也就是consul控制台的服务名字
cloud:
openfeign:
httpclient: #开启hc5的httpclient
hc5:
enabled: true #开启是true
client:
config:
default: #default全局配置 PayService的话就是指定服务的时间
connect-timeout: 3000 #连接时间
read-timeout: 3000 #默认60秒 也就是读取超时,调用其他服务的超时时间
PayService: #default全局配置 PayService的话就是指定服务的时间(优先级高)
connect-timeout: 3000 #连接时间
read-timeout: 5000 #默认60秒 也就是读取超时,调用其他服务的超时时间
consul:
port: 8500
host: localhost
discovery:
service-name: ${spring.application.name}
prefer-ip-address: true #优先使用ip注册
3:验证
7:openfeign请求响应压缩
原文链接:07-OpenFeign-HTTP压缩优化_openfeign accept-encoding=gzip-CSDN博客
gzip是一种数据格式,采用用deflate算法压缩数据;gzip是一种流行的数据压缩算法,应用十分广泛,尤其是在Linux平台。
当GZIP压缩到一个纯文本数据时,效果是非常明显的,大约可以减少70%以上的数据大小。
网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。
查询全部数据压缩前
7.1:8080开启压缩只需要开启配置
spring:
application:
name: Consumer2_OpenFeign #也就是consul控制台的服务名字
cloud:
openfeign:
compression:
request:
enabled: true #request开启压缩
mime-types: text/xml,application/xml,application/json #触发压缩数据格式
min-request-size: 1 #开启压缩的阈值,请求体大小,单位字节,默认2048,即是2k,这里为了演示效果设置成10字节
response:
enabled: true
7.2:8080效果检查(实际上没成功,数据量是44974)
http://localhost:8080/consumer/pay/getALL
7.3:服务端8091设置压缩
server:
compression:
enabled: true #spring项目开启压缩
# min-response-size: 2KB
port: 8091
7.4:服务端8091设置压缩验证
直接访问服务端
http://localhost:8091/pay/getALL
数据截图
8:openFeign日志
开启日志对feign的接口接口调用进行监控
8.1:自定义类
/**
* 开启feign的日志,枚举有四个类型
* NONE,
* BASIC,
* HEADERS,
* FULL;
* @return
*/
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
8.2:配置文件
#logging.level.接口名字:debug
#开启feign的日志
logging:
level:
org: #feignApi包的名字
example:
cloudapi_commoms:
Apis:
PayFeignApi: debug