当前位置: 首页 > news >正文

SpringCloud快速通关(中)

一.OpenFeign

OpenFeign,是一种 Declarative REST Client,即声明式 Rest 客户端,与之对应的是编程式 Rest 客户端,比如 RestTemplate。

OpenFeign 由注解驱动:

  • 指定远程地址:@FeignClien
  • 指定请求方式:@GetMapping@PostMapping@DeleteMapping...
  • 指定携带数据:@RequestHeader@RequestParam@RequestBody...
  • 指定返回结果:响应模式

其中的 @GetMapping 等注解可以沿用 Spring MVC:

  • 当它们标记在 Controller 上时,用于接收请求
  • 当他们标记在 FeignClien 上时,用于发送请求

1.1 远程调用

声明式实现

(1)使用时引入以下依赖:(之前已经引入过)

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

(2)在需要调用别的微服务的主启动类上使用以下注解:

开启Feign远程调用功能用: @EnableFeignClients

开启Feign远程调用功能用: @EnableFeignClients

开启Feign远程调用功能用: @EnableFeignClients

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

(3)编写远程调用的客户端

标识Feign客户端用:@FeignClient!!!

标识Feign客户端用:@FeignClient!!!

标识Feign客户端用:@FeignClient!!!

package com.heima.feign;import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(value = "service-product")//标识Feign客户端
public interface ProductFeignClient {//mvc注解的两套使用逻辑//1.标注在controller上的,是接受这样的请求//2.标注在FeignClient上的,是发送这个服务@GetMapping("/product/{id}")Product getProductById(@PathVariable("id") Long id);
}

现在我们修改OrderServiceImpl

    @Autowiredprivate ProductFeignClient productFeignClient;@Overridepublic Order createOrder(Long userId, Long productId) {//现在改用注入FeignClient//将之前注释掉Product product = getProductFromRemoteWithLoadBalancerAnno(productId);Product product = productFeignClient.getProductById(productId);//以下代码不变}

输出结果:

第三方API

当我们想要向第三方API远程调用(比如使用阿里云为我们提供的天气的API),但是此时变不需要注册中心了,我们也可以使用OpenFeign

//http://aLiv18.data.moji.com/whapi/json/aLicityweather/condition
@FeignClient(value = "weather-client", url = "http://aLiv18.data.moji.com")//因为不需要使用到注册中心,所以value随便写,但是url要精确指定
public interface WeatherFeignClient {@PostMapping("/whapi/json/aLicityweather/condition")String getWeather(@RequestHeader("Authorization") String auth,@RequestParam("token") String token,@RequestParam("cityId") String cityId);
}

技巧:

如何编写好 OpenFeign 声明式的远程调用接口:

  • 针对业务 API:直接复制对方的 Controller 签名即可;
  • 第三方 API:根据接口文档确定请求如何发

vs

面试题:

客户端负载均衡与服务端负载均衡的区别:

1.2 进阶配置

日志

在配置文件中指定 feign 接口所在包的日志级别:

logging:level:# 指定 feign 接口所在的包的日志级别为 debug 级别com.heima.feign: debug

向 Spring配置类容器中注册 feign.Logger.Level 对象:

@Bean
public Logger.Level feignlogLevel() {// 指定 OpenFeign 发请求时,日志级别为 FULLreturn Logger.Level.FULL;
}

超时控制

连接超时(connectTimeout),控制第一步建立连接的时间,不配置的话默认 10 秒。

读取超时(readTimeout),默认 60 秒。

如果需要修改默认超时时间,新建application-feign配置文件中进行如下配置:

spring:cloud:openfeign:client:config:# 默认配置default:logger-level: fullconnect-timeout: 1000read-timeout: 2000# 具体 feign 客户端的超时配置,即@FeignClient中的value值service-product:logger-level: full# 连接超时,3000 毫秒connect-timeout: 3000# 读取超时,5000 毫秒read-timeout: 5000

重试机制

远程调用超时失败后,还可以进行多次尝试,如果某次成功则返回 ok,如果多次尝试后依然失败则结束调用,返回错误。

OpenFeign 底层默认使用 NEVER_RETRY,即从不重试策略。

向 Spring 容器中Config类里面添加 Retryer 类型的 Bean:

@Bean
public Retryer retryer() {return new Retryer.Default();
}

拦截器

以请求拦截器为例,自定义的请求拦截器需要实现 RequestInterceptor 接口,并重写 apply() 方法:

(1)新键interceptor包,编写类

package com.heima.interceptor;import feign.RequestInterceptor;
import feign.RequestTemplate;import java.util.UUID;public class XTokenRequestInterceptor implements RequestInterceptor {/*** 请求拦截器** @param template 封装本次请求的详细信息*/@Overridepublic void apply(RequestTemplate template) {System.out.println("XTokenRequestInterceptor ...");template.header("X-Token", UUID.randomUUID().toString());}
}

要想要该拦截器生效有两种方法:

  1. 在application-feign.yml配置文件中配置对应 Feign 客户端的请求拦截器,此时该拦截器只对指定的 Feign 客户端生效

spring:cloud:openfeign:client:config:# 具体 feign 客户端service-product:# 该请求拦截器仅对当前客户端有效request-interceptors:- com.heima.interceptor.XTokenRequestInterceptor

  2. 还可以直接将自定义的请求拦截器添加到 Spring 容器中,此时该拦截器对服务内的所有 Feign客户端生效

@Component
public class XTokenRequestInterceptor implements RequestInterceptor {// --snip--
}

Fallback兜底返回

Fallback,即兜底返回。注意,此功能需要整合 Sentinel 才能实现。

(1) 在order-service中需要先导入 Sentinel 依赖:

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

 (2) 并在需要进行 Fallback 的服务的application-feign.yml配置文件中开启配置:

feign:sentinel:enabled: true

(3) 在feign包下建立新的fallback包

package com.heima.feign.fallback;@Component
//实现ProductFeignClient接口,调用远程客户端的时候找不到远程服务,就会调用这个类(假数据)
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getProductById(Long id) {System.out.println("兜底回调...");Product product = new Product();product.setId(id);product.setPrice(new BigDecimal("0"));product.setProductName("未知商品");product.setNum(0);return product;}
}

(4)之后回到对应的 Feign 客户端,配置 Fallback:

@FeignClient(value = "service-product", fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {@GetMapping("/product/{id}")Product getProductById(@PathVariable("id") Long id);
}

二.Sentinel

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Spring Cloud Alibaba Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。

定义资源:

  • 主流框架自动适配(Web Servlet、Dubbo、Spring Cloud、gRPC、Spring WebFlux、Reactor),所有 Web 接口均为资源

  • 编程式:SphU API

  • 声明式:@SentinelResource

定义规则:

  • 流量控制(FlowRule)

  • 熔断降级(DegradeRule)

  • 系统保护(SystemRule)

  • 来源访问控制(AuthorityRule)

  • 热点参数(ParamFlowRule)

2.1 整合Sentinel

启动 Dashboard

前往 Sentinel GitHub Realease 页下载 Sentinel Dashboard,这里选择 1.8.8 版本,因此下载 sentinel-dashboard-1.8.8.jar

 sentinel-dashboard-1.8.8.jar 所在的目录运行以下命令,启动 Dashboard:

java -jar sentinel-dashboard-1.8.8.jar

启动完成后,浏览器访问 http://localhost:8080/,默认用户与密码均为 sentinel

注意:关闭sentinel我们通过在终端ctrl+c进行关闭

服务整合 Sentinel

java -jar sentinel-dashboard-1.8.8.jar

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

(2) 配置文件中添加:

spring:application:name: service-productcloud:sentinel:transport:# 控制台地址dashboard: localhost:8080# 立即加载服务 eager: true

(3) 配置完成后启动对应服务,再前往 Sentinel Dashboard 查看,能够看到对应服务信息。

(4) 可以在一个方法上使用 @SentinelResource 注解,将其标记为一个「资源」,当方法被调用时,能够在 Dashboard 的「簇点链路」上找到对应的资源,之后在界面上完成对资源的流控、熔断、热点、授权等操作。

eg:假如我认为创建订单createOrder是一个资源,我将来想要保护它,对它进行一些流控制等规则限制

    .............@SentinelResource(value = "createOrder")@Overridepublic Order createOrder(Long userId, Long productId) {}

此时

2.2异常处理

Web接口

(1)在model模块下新建一个包common,创建类R

package com.common;import lombok.Data;@Data
public class R {private Integer code;private String msg;private Object data;public static R ok() {R r = new R();r.setCode(200);return r;}public static R ok(Object data){R r = new R();r.setCode(200);r.setData(data);return r;}public static R error(){R r = new R();r.setCode(500);return r;}public static R error(Integer code,String msg){R r = new R();r.setCode(code);r.setMsg(msg);return r;}
}

(2)在service-order模块下新建包exception,创建自定义的类MyBlockExceptionHandler ,可以实现 BlockExceptionHandler 接口,并将实现类交给 Spring 管理

package com.heima.exception;import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.common.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;import java.io.PrintWriter;@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {private final ObjectMapper objectMapper;public MyBlockExceptionHandler(ObjectMapper objectMapper) {this.objectMapper = objectMapper;}@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,String resourceName,BlockException e) throws Exception {response.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();R error = R.error(500, resourceName + " 被 Sentinel 限制了, 原因: " + e.getClass());String json = objectMapper.writeValueAsString(error);writer.write(json);writer.flush();writer.close();}
}

此时多次访问

@SentinelResource

当 @SentinelResource 注解标记的资源被流控时,默认返回 500 错误页。

如果需要自定义异常处理,一般可以增加 @SentinelResource 注解的以下任意配置:

  • blockHandler

  • fallback

  • defaultFallback

以 blockHandler 为例:

@SentinelResource(value = "createOrder", blockHandler = "createOrderFallback")
public Order createOrder(Long productId, Long userId) {// --snip--
}

在当前类中创建名称为 blockHandler 值的方法,并且返回值类型、参数信息与 @SentinelResource 标记的方法一致(可以额外增加一个 BlockException 类型的参数):

/**
* 指定兜底回调
*/
public Order createOrderFallback(Long productId, Long userId, BlockException e) {Order order = new Order();order.setId(0L);order.setTotalAmount(new BigDecimal("0"));order.setUserId(userId);order.setNickname("未知用户");order.setAddress("异常信息: " + e.getClass());return order;
}

此时多次访问该界面,会得到:

Feign 接口

当 Feign 接口作为资源并被流控时,如果调用的 Feign 接口指定了 fallback,那么就会使用 Feign 接口的 fallback 进行异常处理,否则由 SpringBoot 进行全局异常处理。

http://www.dtcms.com/a/606499.html

相关文章:

  • 性价比高的时序数据库哪个专业
  • 邵阳高端网站建设做响应式网站的物流
  • 网站定制开发哪家厉害网站登录界面源码
  • 自己电脑做网站服务器违法吗上海网站建设最好的公司排名
  • C++-vector-back子函数和std::move函数详细介绍
  • 07.指针
  • 【gas优化】2.9 使用sstore2或sstore3存储大量数据
  • 来宾北京网站建设网站浏览思路
  • 网站建设模式化的体现企业个人邮箱怎么注册
  • 分布式部署
  • 保障电网安全,赋能绿色能源:AM5SE-PV系列主从机防逆流保护装置在江西丰城曲江煤炭开发公司5.8MW分布式光伏项目的关键角色
  • C/C++ Linux网络编程3 - Socket编程与TCP服务器客户端
  • 镇江大港南站wordpress 新闻 通知
  • 【ZeroRange WebRTC】RFC 5389:STUN 协议规范(中文整理与译注)
  • 苏州网站制作及推广二手闲置平台网站怎么做
  • Unity零碎物体合并为一个整体mesh
  • 做响应式网站图片需要做几版在哪个网站找学做包子
  • 国内大型php网站建设商务网站开发背景
  • HarmonyOS开发-ArkWeb开发指导
  • kotlin:if、when语句介绍
  • 扩展函数练习题
  • Java后端常用技术选型 |(一)数据库篇
  • 婚纱摄影网站应该如何做优化室内装修设计软件下载
  • 从零开始写算法——二分-寻找旋转排序数组中的最小值
  • 一站式网站建设与运营简述网站开发平台及常用工具
  • 易语言程序反编译 | 深入了解反编译技术与应用
  • 本地部署数据库管理工具 NocoDB 并实现外部访问(Linux 版本)
  • 9V-36V转3.3V4A同步降压WT6043A
  • P10668 BZOJ2720 [Violet 5] 列队春游(自己加强版) 题解
  • 学做立体书的网站wordpress小人插件