目录

一.创建微服务项目

(一)环境准备

(二)项目结构图

(三)流程

二. Nacos

(一)注册中心

1.服务注册

2.服务发现

3.编写微服务API

4.远程调用基本实现

5.负载均衡

6.@LoadBalanced注解式注解均衡

7.注册中心宕机,远程调用还能成功吗

(二)配置中心

1.基本用法

2. 动态刷新

3. 配置监听

4.Nacos中的数据集和application.properties有相同的配置项,哪个生效?

5. 数据隔离

三. OpenFeign

(一)远程调用

1.声明式实现(业务API)

2. 第三方API

3.小技巧与面试题

(二)进阶配置

1. 日志

2. 超时控制

3.重试机制

4. 拦截器

5.Fallback

四.Sentinel

(一)基础

(二)整合使用

(三)异常处理

1.Web接口自定义处理异常

2. @SentinelResource

3. OpenFeign

(四)流控规则

1. 流量模式-直接

2. 流量模式-链路

3. 流量模式-关联

4. 流量效果-直接

5.流量效果-Warm Up

6. 流量效果-匀速排队

(五)熔断规则

1. 断路器工作原理

2. 熔断策略-慢调用比例

3.熔断策略-异常比例

4.熔断策略-异常数

(六)热点规则

五.Gateway

(一)网关功能

(二)创建网关

(三)路由

1. 规则配置

2.原理

3. 断言

(四)过滤器​编辑

1.路径重写

2.默认fliter

3.全局过滤器

4. 全局跨域

六. Seata-分布式事务

(一)架构原理 

(二) 二阶提交协议

(三)XA模式

(四)AT模式


一.创建微服务项目

(一)环境准备

• 创建微服务架构项目

• 引入 SpringClould、Spring Cloud Alibaba 相关依赖

• 注意版本适配

https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明

版本选择:

(二)项目结构图

 

(三)流程

把这些删掉:

在pom.xml里加上这一行表示为父项目:

 <packaging>pom</packaging>

把这些依赖删掉:

加上:

 <properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-cloud.version>2023.0.3</spring-cloud.version><spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version></properties><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><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement>

把springboot版本换成3.3.4:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.4</version><relativePath/> 
</parent>

创建子模块:

在子项目pom.xml中写入并刷新并将src删了:

<packaging>pom</packaging>

在services中创建几个微服务

在services的pom.xml中写入:

 <dependencies><!--服务发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
</dependencies>

二. Nacos

注册中心:

安装:

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首 字母简称,一个更易于构建云原生应用的动态服务发现、配置管 理和服务管理平台。

官网:https://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html

启动命令: startup.cmd -m standalone

下载后解压进入bin文件夹,打开cmd输入startup.cmd -m standalone

打开浏览器访问localhost:8848/nacos/可访问

(一)注册中心

1.服务注册

在services-order中的pom.xml里写:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

在services-order中写启动类并在resources中新建文件application.properties并写入,运行启动类后nacos的服务列表中会自动创建服务

@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class,args);}
}
spring.application.name=service-order
server.port=8000spring.cloud.nacos.server-addr=127.0.0.1:8848

同理services-products中也这么做

idea配置微服务:

点击运行配置类型选择springboot

复制服务:

鼠标右键点击复制配置:

点击修改选项:

点击程序实参:

写端口号并点击应用:

2.服务发现

在启动类上加注解@EnableDiscoveryClient

@EnableDiscoveryClient // 开启服务发现功能
@SpringBootApplication
public class ProductsMainApplication {public static void main(String[] args) {SpringApplication.run(ProductsMainApplication.class,args);}
}

导入测试依赖:

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>

新建测试类:

@SpringBootTest
public class DiscoveryTest {@AutowiredDiscoveryClient discoveryClient;@AutowiredNacosServiceDiscovery nacosServiceDiscovery;@Testvoid  nacosServiceDiscoveryTest() throws NacosException {for (String service : nacosServiceDiscovery.getServices()){System.out.println("service="+service);//获取ip+portList<ServiceInstance> instances=nacosServiceDiscovery.getInstances(service);for (ServiceInstance instance : instances){System.out.println("ip:"+instance.getHost()+";"+" post="+instance.getPort());}}}@Testvoid discoveryClientTesr(){for (String service : discoveryClient.getServices()){System.out.println("service="+service);//获取ip+portList<ServiceInstance> instances=discoveryClient.getInstances(service);for (ServiceInstance instance : instances){System.out.println("ip:"+instance.getHost()+";"+" post="+instance.getPort());}}}
}两个方法运行都能打印:service=service-orderip:192.168.100.1; post=8000service=service-productsip:192.168.100.1; post=9000

3.编写微服务API

远程调用 - 基本流程

远程调用 - 下单场景:

在services中引入lombook

 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>scope>annotationProcessor</scope></dependency>

新建bean,constroller,service

services-product中:

@Data
public class Product {private Long id;private BigDecimal price;private String productName;private int num;
}@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId){Product product=productService.getProductById(productId);return product;}
}public interface ProductService {Product getProductById(Long productId);
}@Service
public class ProductServiceimpl implements ProductService {@Overridepublic Product getProductById(Long productId) {Product product=new Product();product.setId(productId);product.setPrice(new BigDecimal("99"));product.setProductName("苹果"+productId);product.setNum(2);return product;}
}

运行启动类后:

services-order中:

@Data
public class Order {private Long id;private BigDecimal totalAmount;private Long userId;private  String nickName;private  String address;private List<Object> productList;
}@RestController
public class OrderController {@AutowiredOrderService orderService;//创建订单@GetMapping("/create")public Order createOrder(@RequestParam("userId") Long userId,@RequestParam("productId")Long productId){Order order = orderService.createOrder(productId,userId);return order;}
}public interface OrderService {Order createOrder(Long productId,Long userId);
}@Service
public class OrderServiceImpl implements OrderService {@Overridepublic Order createOrder(Long productId, Long userId) {Order order = new Order();order.setId(1L);order.setTotalAmount(new BigDecimal("0"));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");order.setProductList(null);return order;}
}

运行启动类后:

4.远程调用基本实现

订单和商品都启动多个实例:

要在访问订单时也能访问到商品的数据

因为在services-order中访问不到Product类,所有在cloud-demo下一级新建一个model模块,把订单模块和商品模块的bean都复制到model中并把订单和商品模块中的bean删掉,将model模块引入lombook,将services中引入model模块这样在订单和商品模块就能用model中的bean了

在订单模块创建一个配置类:

@Configuration
public class OrderConfig {@BeanRestTemplate restTemplate(){return new RestTemplate();  //restTemplate用于给远程发送请求}
}

OrderServiceImpl:

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@Overridepublic Order createOrder(Long productId, Long userId) {Product product=getProductFromRemote(productId);Order order = new Order();order.setId(1L);//总金额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");//远程查询商品列表order.setProductList(Arrays.asList( product));return order;}private Product getProductFromRemote(Long productId){//1.获取到商品服务所在的所有机器ip+portList<ServiceInstance> instances=discoveryClient.getInstances("service-products");ServiceInstance instance=instances.get(0);//远程URLString url="http://"+instance.getHost()+":"+instance.getPort()+"/product/"+productId;log.info("远程请求:{}",url);//2.给远程发送请求Product product=restTemplate.getForObject(url,Product.class);return product;}
}

将Order类中的集合类型改为Product:

@Data
public class Order {private Long id;private BigDecimal totalAmount;private Long userId;private  String nickName;private  String address;private List<Product> productList;
}

将所有服务全部重启:

浏览器向订单发起请求:

如果把9001,9002,,9003关掉一个或两个那也能照常运行,比如关掉9001就会使用9002或9003。

缺点:每次都会给固定位置发请求,比如第一次给9001,那以后都是9001,除非9001被关掉

5.负载均衡

在services-order中引入spring-cloud-starter-loadbalancer以及测试类

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>
</dependency>

新增测试类:

@SpringBootTest
public class LoadBalancerTest {@AutowiredLoadBalancerClient loadBalancerClient;@Testvoid test(){ServiceInstance choose=loadBalancerClient.choose("service-products");System.out.println("choose =" +choose.getHost()+": "+choose.getPort());ServiceInstance choose2=loadBalancerClient.choose("service-products");System.out.println("choose =" +choose2.getHost()+": "+choose2.getPort());ServiceInstance choose3=loadBalancerClient.choose("service-products");System.out.println("choose =" +choose3.getHost()+": "+choose3.getPort());ServiceInstance choose4=loadBalancerClient.choose("service-products");System.out.println("choose =" +choose4.getHost()+": "+choose4.getPort());}
}

运行显示:

OrderServiceImpl:

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredRestTemplate restTemplate;@Autowired  //一定导入spring-cloud-starter-loadbalancerLoadBalancerClient loadBalancerClient;@Overridepublic Order createOrder(Long productId, Long userId) {Product product=getProductFromRemoteWithLoadBalance(productId);Order order = new Order();order.setId(1L);//总金额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");//远程查询商品列表order.setProductList(Arrays.asList( product));return order;}//完成负载均衡发送请求private Product getProductFromRemoteWithLoadBalance(Long productId){//1.获取到商品服务所在的所有机器ip+portServiceInstance choose = loadBalancerClient.choose("service-products");//远程URLString url="http://"+choose.getHost()+":"+choose.getPort()+"/product/"+productId;log.info("远程请求:{}",url);//2.给远程发送请求Product product=restTemplate.getForObject(url,Product.class);return product;}
}

多次向订单发起请求后端口一直在循环:

6.@LoadBalanced注解式注解均衡

在配置类中加上注解:

@Configuration
public class OrderConfig {@LoadBalanced //注解式负载均衡@BeanRestTemplate restTemplate(){return new RestTemplate();}
}

OrderServiceImpl:

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredRestTemplate restTemplate;@Overridepublic Order createOrder(Long productId, Long userId) {Product product=getProductFromRemoteWithLoadBalanceAnnotation(productId);Order order = new Order();order.setId(1L);//总金额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");//远程查询商品列表order.setProductList(Arrays.asList( product));return order;}//基于注解的负载均衡private Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId){String url="http://service-products/product/"+productId;//2.给远程发送请求   service-products(微服务名字)会被动态替换Product product=restTemplate.getForObject(url,Product.class);return product;}
}

在ProductController中添加输出语句:

@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId){System.out.println("hello");Product product=productService.getProductById(productId);return product;}
}

运行后多次请求会发现循环在9001,9002,9003三个控制台输入hello

7.注册中心宕机,远程调用还能成功吗

没调⽤过如果宕机,调⽤会失败

调⽤过如果宕机,因为会缓存名单,远程调用不在依赖注册中心,所以调⽤会成功

(二)配置中心

1.基本用法

配置中心 - 基本使用:

在services下引入nacos作为配置中心的依赖:

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

在service-order中的application.properties中写入:

spring.cloud.nacos.server-addr=127.0.0.1:8848
spring.config.import=nacos:service-order.properties

点击创建配置:

输入Date ID 配置格式和配置内容并点击发布:

在OrderController中获取配置文件中的配置值,

@RefreshScope  //自动刷新
@RestController
public class OrderController {@AutowiredOrderService orderService;@Value("${order.timeout}")String orderTimeout;@Value("${order.auto-confirm}")String orderAutoConfirm;@GetMapping("/config")public String config(){return "order.timeout="+orderTimeout+": order.auto-confirm="+orderAutoConfirm;}//创建订单@GetMapping("/create")public Order createOrder(@RequestParam("userId") Long userId,@RequestParam("productId")Long productId){Order order = orderService.createOrder(productId,userId);return order;}
}

运行启动类并在浏览器输入http://localhost:8000/config则可以看到,@RefreshScope注解表示激活配置属性的自动刷新功能,就是如果在nacos中修改了配置,刷新浏览器就可以自动修改值,如果不加这个注解值就不会变

注意:如果引入了配置中心但项目启动没有导入任何配置就会报错,这时候需要在application.properties中写:

#禁用导入检查
spring.cloud.nacos.config.import-check.enabled=false

2. 动态刷新

使用步骤

  • @Value(“${xx}”) 获取配置 + @RefreshScope 实现自动刷新
  • @ConfigurationProperties 无感自动刷新
  • NacosConfigManager 监听配置变化

将经常用的配置可以抽取到一个Properties类中,新建OrderProperties类

@Component
@ConfigurationProperties(prefix = "order")   //prefix写配置项中.前面的
//配置批量绑定在nacos中,可以无需@RefreshScope就能实现自动刷新
@Data
public class OrderProperties {String timeout;   //属性名写配置项中.后面的。String autoConfirm; //如果是短横线写法就写成驼峰命名方式
}

OrderController中:

@RestController
public class OrderController {@AutowiredOrderService orderService;@AutowiredOrderProperties orderProperties;@GetMapping("/config")public String config(){return "order.timeout="+orderProperties.getTimeout()+": order.auto-confirm="+orderProperties.getAutoConfirm();}//创建订单@GetMapping("/create")public Order createOrder(@RequestParam("userId") Long userId,@RequestParam("productId")Long productId){Order order = orderService.createOrder(productId,userId);return order;}
}

3. 配置监听

OrderMainApplication中:

@EnableDiscoveryClient
@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class,args);}//1. 项目启动就监听配置文件变化//2. 发生变化后拿到变化值//3. 发送邮件@BeanApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager){return  args-> {ConfigService configService= nacosConfigManager.getConfigService();configService.addListener("service-order.properties","DEFAULT_GROUP", new Listener() {@Overridepublic Executor getExecutor() {return Executors.newFixedThreadPool(4);}@Overridepublic void receiveConfigInfo(String configInfo) {System.out.println("变化的配置信息:"+configInfo);System.out.println("邮件通知...");}});System.out.println("启动");};}
}

启动服务后修改nocos中配置的值后控制台打印:

4.Nacos中的数据集和application.properties有相同的配置项,哪个生效?

spring.cloud.nacos.server-addr=127.0.0.1:8848
#导入多个配置
spring.config.import=nacos:service-order.properties,nacos:common.properties

后导入优先,外部优先

5. 数据隔离

需求描述:

  •   项目有多套环境:dev,test,prod
  •   每个微服务,同一种配置,在每套环境的值都不一样。                                                             如:database.properties                                                                                                     如:common.properties
  •   项目可以通过切换环境,加载本环境的配置

难点 :

  •    区分多套环境
  •    区分多种微服务
  •    区分多种配置
  •    按需加载配置

把application.properties去掉换成application.yml,注意yml里不能出现注释,有注释会报错,复制下面的时候要把注释删了

server:port: 8000
spring:profiles:active: prod  #激活哪个环境application:name: service-ordercloud:nacos:server-addr: 127.0.0.1:8848config:namespace: ${spring.profiles.active:public}   #动态取值,:表示默认public---   #---是多文档模式
spring:config:import:- nacos:common.properties?group=order  #?后面表示导入哪个组命名空间下的配置文件- nacos:database.properties?group=orderactivate:  #在哪种环境下生效on-profile: dev
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: test
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: prod

三. OpenFeign

(一)远程调用

1.声明式实现(业务API)

Declarative REST Client

声明式 REST 客户端 vs 编程式 REST 客户端(RestTemplate)

注解驱动 : 

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

在services中引入依赖:

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

远程调用 - 业务API:

在订单的启动类中加上注解@EnableFeignClients

@EnableFeignClients //开启Feign的远程调用功能
@EnableDiscoveryClient
@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class,args);}//1. 项目启动就监听配置文件变化//2. 发生变化后拿到变化值//3. 发送邮件@BeanApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager){return  args-> {ConfigService configService= nacosConfigManager.getConfigService();configService.addListener("service-order.properties","DEFAULT_GROUP", new Listener() {@Overridepublic Executor getExecutor() {return Executors.newFixedThreadPool(4);}@Overridepublic void receiveConfigInfo(String configInfo) {System.out.println("变化的配置信息:"+configInfo);System.out.println("邮件通知...");}});System.out.println("启动");};}
}

编写一个远程调用的客户端:

@FeignClient(value = "service-products") //feign客户端
public interface ProductFeignClient {//mvc注解的两套使用逻辑//1. 标注在Controller上,是接受这样的请求//2. 标注在FeignClient上,是发送这样的请求@GetMapping("/product/{id}")Product getProductById(@PathVariable("id")Long id);
}

修改OrderServiceImpl中创建订单的逻辑:

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredProductFeignClient productFeignClient;@Overridepublic Order createOrder(Long productId, Long userId) {//使用Feign完成远程调用Product product=productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);//总金额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");//远程查询商品列表order.setProductList(Arrays.asList( product));return order;}
}

运行后浏览器访问:

OpenFeign能自动实现负载均衡

2. 第三方API

编写一个远程调用的客户端:

//http://aliv18.data.moji.com/whapi/json/alicityweather/condition
@FeignClient(value = "weather-client",url ="http://aliv18.data.moji.com" )
//因为是第三方api,没有注册中心的名字,所以value随便写
public interface WeatherFeignCilent {@PostMapping("/whapi/json/alicityweather/condition")String getWeather(@RequestHeader("Authorization") String auth,@RequestParam("token") String Token,@RequestParam("cityId") String cityId);
}

新增测试类:

@SpringBootTest
public class WeatherTest {@AutowiredWeatherFeignCilent weatherFeignCilent;@Testvoid test01(){String weather=weatherFeignCilent.getWeather("APPCODE 93b7e19861a24c519a7548b17dc16d75","50b53ff8dd7d9fa320d3d3ca32cf8ed1","2182");System.out.println("weather = "+weather);}
}

3.小技巧与面试题

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

      业务API:直接复制对方Controller签名即可

      第三方API:根据接口文档确定请求如何发

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

(二)进阶配置

1. 日志

在yml文件添加:

logging:level:com.itheima.feign: debug

注意:这里的com.itheima.feign是自己定义的feign客户端的包名

包名这样取:

在配置类中添加:

@Bean
Logger.Level feignLoggerLevel() {return Logger.Level.FULL;
}

2. 超时控制

在ProductServiceimpl中添加睡眠代码:

@Service
public class ProductServiceimpl implements ProductService {@Overridepublic Product getProductById(Long productId) {Product product=new Product();product.setId(productId);product.setPrice(new BigDecimal("99"));product.setProductName("苹果"+productId);product.setNum(2);try {TimeUnit.SECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}return product;}
}

打开浏览器访问会等待60秒,然后显示:

控制台报错:

超时配置:

services-order的application.yml中增加:

server:port: 8000
spring:profiles:active: prod#include是包含的意思,包含feign,feign就是下面新建的文件application-feign的-后面部分include: feign   application:name: service-ordercloud:nacos:server-addr: 127.0.0.1:8848config:namespace: ${spring.profiles.active:pubilc}logging:level:com.itheima.feign: debug---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: dev
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: test
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: prod

新建application-feign.yml文件:

spring:cloud:openfeign:client:config:default: #默认设置logger-level: fullconnect-timeout: 1000  #连接超时read-timeout: 2000   #读取超时service-products:  #精确设置logger-level: fullconnect-timeout: 3000read-timeout: 5000

3.重试机制

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

第一次请求失败后间隔100毫秒重新发送,第二次请求失败后间隔(100*1.5)毫秒重新发送,第三次请求失败后间隔(100*1.5*1.5)毫秒后重新发送......最大不能超过1秒,超过按1秒算。


在配置类中加上:

 @BeanRetryer retryer(){return new Retryer.Default();}//不传参数就是间隔100毫秒,最大间隔1秒,最多尝试5次

4. 拦截器

创建一个拦截器:

@Component
public class XTokenRequestInterceptor implements RequestInterceptor {/*** 请求拦截器* @param requestTemplate */@Overridepublic void apply(RequestTemplate requestTemplate) {System.out.println("请求拦截器启动");requestTemplate.header("X-Token","123456");}
}

在ProductController中可以取出X-token:

@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId,HttpServletRequest request){System.out.println(request.getHeader("X-Token"));System.out.println("hello");Product product=productService.getProductById(productId);return product;}
}

重新运行并访问就能打印值

5.Fallback

引⼊ sentinel:

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

在yml文件开启熔断:

feign:sentinel:enabled: true

兜底回调:

@Component
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;}
}

修改ProductFeignClient接口:

@FeignClient(value = "service-products",fallback = ProductFeignClientFallback.class)
//feign客户端    fallback表示该客户端调用失败了用哪个做兜底
public interface ProductFeignClient {//mvc注解的两套使用逻辑//1. 标注在Controller上,是接受这样的请求//2. 标注在FeignClient上,是发送这样的请求@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)

工作原理:

(二)整合使用

下载控制台:https://security.feishu.cn/link/safety?target=https%3A%2F%2Fgithub.com%2Falibaba%2FSentinel%2Freleases&scene=ccm&logParams=%7B%22location%22%3A%22ccm_docs%22%7D&lang=zh-CN

在下载后存放jar的文件夹输入cmd,在cmd输入java -jar sentinel-dashboard-1.8.8.jar

访问8080就是sentinel控制台,默认账号密码就是sentinel

在services中引入sentinel依赖

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

在两个微服务模块的application-feign.yml和application.properties中写入:

spring:cloud:openfeign:client:config:default:logger-level : fullconnect-timeout: 1000read-timeout: 2000service-products:logger-level: fullconnect-timeout: 3000read-timeout: 5000sentinel:transport:dashboard: localhost:8080eager: true
feign:sentinel:enabled: true
spring.application.name=service-products
server.port=9001spring.cloud.nacos.server-addr=127.0.0.1:8848spring.cloud.nacos.config.import-check.enabled=falsespring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true

运行订单和商品模块浏览器控制台就会显示:

在OrderServiceImpl中给createOrder添加注解 @SentinelResource(value = "createOrder"):

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredProductFeignClient productFeignClient;@SentinelResource(value = "createOrder")@Overridepublic Order createOrder(Long productId, Long userId) {//使用Feign完成远程调用Product product=productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);//总金额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");//远程查询商品列表order.setProductList(Arrays.asList( product));return order;}
}

重新运行订单模块并在浏览器请求

sentinel控制台的簇点链路会出现:

点击create右边的流控,并把单机阈值设为1(QPS表示每秒请求数量,单机阈值为1表示每秒最多请求1次)并点击新增:

流控规则中会显示:

用浏览器频繁刷新(每秒超过一个请求)会显示:

(三)异常处理

1.Web接口自定义处理异常

在service-order中⾃定义异常处理类BlockExceptionHandler:

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {private ObjectMapper objectMapper=new ObjectMapper();@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,String resourseName, BlockException e) throws Exception {response.setContentType("application/json;charset=utf-8");PrintWriter writer = response.getWriter();R error=R.error(500,resourseName+"被Sentinel限制了,原因:"+e.getClass());String json=objectMapper.writeValueAsString(error); //将对象转成字符串writer.write(json);writer.flush();writer.close();}
}

在model模块新建R对象:

@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(String msg, Object data) {R r = new R();r.setCode(200);r.setMsg(msg);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. @SentinelResource

给createOrder添加流控规则:

为了方便测试把之前/create的流程规则删了

如果在一秒内频繁刷新浏览器会显示一个默认的错误页:

修改OrderServiceImpl(如果被@SentinelResource标注的资源没用违反规则则调用真实业务逻辑并返回真实数据,如果违反了规则被Sentinel限制了,则调用blockHandler指定的方法返回兜底数据):

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {@AutowiredProductFeignClient productFeignClient;@SentinelResource(value = "createOrder",blockHandler = "createOrderFallback")//blockHandler指定兜底回调@Overridepublic Order createOrder(Long productId, Long userId) {//使用Feign完成远程调用Product product=productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);//总金额order.setTotalAmount(product.getPrice().multiply(new BigDecimal(product.getNum())));order.setUserId(userId);order.setNickName("zhangsan");order.setAddress("尚硅谷");//远程查询商品列表order.setProductList(Arrays.asList( product));return order;}//执行兜底回调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;}
}

重新启动订单服务,并在一秒内频繁刷新页面显示:

3. OpenFeign

为远程调用添加流控:

因为之前编写OpenFeign客户端的时候指定了一个Fallback回调,所以只要失败了就会调用兜底回调

@FeignClient(value = "service-products",fallback = ProductFeignClientFallback.class) //feign客户端
public interface ProductFeignClient {//mvc注解的两套使用逻辑//1. 标注在Controller上,是接受这样的请求//2. 标注在FeignClient上,是发送这样的请求@GetMapping("/product/{id}")Product getProductById(@PathVariable("id")Long id);
}
@Component
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;}
}

一秒内多次刷新就会显示:

(四)流控规则

1. 流量模式-直接

限制多余请求,从而保护系统资源不被耗尽

QPS: 统计每秒请求数

并发线程数: 统计并发线程数

2. 流量模式-链路

调用关系包括调用方、被调用方;一个方法又可能会调用其它方法,形成一个调用链路的层次关 系;有了调用链路的统计信息,我们可以衍生出多种流量控制手段

在OrderController中新增方法sekill表示秒杀创建订单:

@RestController
public class OrderController {@AutowiredOrderService orderService;@AutowiredOrderProperties orderProperties;@GetMapping("/config")public String config(){return "order.timeout="+orderProperties.getTimeout()+": order.auto-confirm="+orderProperties.getAutoConfirm()+": "+"order.db-url="+orderProperties.getDbUrl();}//创建订单@GetMapping("/create")public Order createOrder(@RequestParam("userId") Long userId,@RequestParam("productId")Long productId){Order order = orderService.createOrder(productId,userId);return order;}//秒杀创建订单@GetMapping("/sekill")public Order sekill(@RequestParam("userId") Long userId,@RequestParam("productId")Long productId){Order order = orderService.createOrder(productId,userId);order.setId(Long.MAX_VALUE);return order;}
}

在yml文件新增配置web-context-unify: false表示不统一web上下文:

spring:cloud:openfeign:client:config:default:logger-level : fullconnect-timeout: 1000read-timeout: 2000service-products:logger-level: fullconnect-timeout: 3000read-timeout: 5000sentinel:transport:dashboard: localhost:8080eager: trueweb-context-unify: falsefeign:sentinel:enabled: true

重新启动Order模块后Sentinel 控制台有两个链路:

对createOrder进行限流

这时候如果访问/create没有流量限制,但请求/sekill就有限制

一秒内访问多次/sekill:

3. 流量模式-关联

在OrderController中新增两个方法:

@GetMapping("writeDb")
public String writeDb(){return "writeDb";
}
@GetMapping("readDb")
public String readDb(){return "readDb";
}

给readDb添加流控:

当/writeDb访问量极大时再访问/readDb就会:

4. 流量效果-直接

注意:只有快速失败支持流控模式(直接、 关联、链路)的设置

给/readDb新增流控:

利用apipost进行压测:

5.流量效果-Warm Up

QPS表示每秒通过几个请求,Period表示预热时常是几秒,比如QPS=3,Period=3,那么如果遇到超高峰流量到达,请求数量会从第一秒1个第二秒2个第三秒3个递增,一直到设置的峰值

重新设置/readDb的流控:

用apipost测压(设成每秒最多并发10个,持续5秒):

查看idea控制台:

第一秒打印3个第一秒还没开始统计,第二秒打印3个,第三秒打印5个,第四秒打印9个,第五秒10个,第六秒10个,idea控制台有误差,但整体趋势是对的

6. 流量效果-匀速排队

每秒两个请求,多余的排队,timeout表示超时时间,超过这个时间就会被丢弃

重新设置/readDb的流控:

使用apipost进行压力测试:

idea控制台:

(五)熔断规则

1. 断路器工作原理

熔断降级(DegradeRule):

2. 熔断策略-慢调用比例

设置熔断:

表示5秒内如果有80%的请求响应时间大于1秒就是慢调用(最少有5个请求),一旦发生慢调用就认为对方是不可靠的就开启熔断30秒,这30秒内的所有请求都不会发给远程服务。

修改ProductController(谁调用商品模块都会休眠2秒):

@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId,HttpServletRequest request){System.out.println(request.getHeader("X-Token"));System.out.println("hello");Product product=productService.getProductById(productId);try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}return product;}
}

重新启动商品模块,浏览器请求http://localhost:8888/create?userId=1&productId=777,5秒内多次刷新,会出现兜底数据,然后30秒内一直是这个数据并且不会像商品模块发送请求。

3.熔断策略-异常比例

修改ProductController故意制造错误:

@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId,HttpServletRequest request){System.out.println(request.getHeader("X-Token"));System.out.println("hello");Product product=productService.getProductById(productId);int i=10/0;return product;}
}

给GET:http://service-products/product/{id}设置新熔断:

5秒内如果异常比例占80%就熔断30秒,30秒内不给商品模块发请求

重启商品模块并在浏览器请求,前五秒频繁刷新会触发熔断,导致30不对商品模块发请求,30秒后会尝试发请求,这时候再不断刷新就又会触发熔断

4.熔断策略-异常数

5秒内异常数超过10个就触发熔断30秒

(六)热点规则

热点参数限流

热点参数:

需求1:

修改OrderController中的sekill方法(添加@SentinelResource注解):

@GetMapping("/sekill")
@SentinelResource(value = "sekill-order",fallback = "sekillFallBack")
// required表示不必填,defaultValue表示默认值
public Order sekill(@RequestParam(value = "userId",defaultValue = "888")Long userId,@RequestParam(value = "productId",required = false)Long productId){Order order = orderService.createOrder(productId,userId);order.setId(Long.MAX_VALUE);return order;
}
public Order sekillFallback(Long userId, Long productId,Throwable exception){System.out.println("sekillFallback...");Order order=new Order();order.setId(productId);order.setUserId(userId);order.setAddress("异常信息:"+exception.getClass());return order;
}fallback与blockHandler兜底回调区别:
使用fallback是有blockHandler优先使用blockHandler,没有blockHandler再使用fallback
fallback可以处理业务异常,如果使用fallback那么兜底回调的异常要写成Throwable
如果使用blockHandler那兜底异常要使用BlockException
否则兜底回调不生效,限流会返回一个默认错误页

添加热点规则:

表示限制第一个参数每秒只能一个,浏览器访问并频繁刷新会:

如果去掉userId参数就没有热点参数限流

需求2:

修改热点规则:

这样6号用户就不被限流了

需求3:

新增热点:

编辑:

五.Gateway

(一)网关功能

Spring Cloud Gateway:

需求:

   1. 客户端发送 /api/order/** 转到 service-order

   2. 客户端发送 /api/product/** 转到 service-product

   3. 以上转发有负载均衡效果

(二)创建网关

在cloud-demo下创建gateway模块

引入依赖:

<dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>
</dependencies>

新建application.yml文件:

spring:application:name: gatewaycloud:nacos:server-addr: 127.0.0.1:8848server:port: 80

新建GatewayMainApplication启动类:

@EnableDiscoveryClient  //服务发现
@SpringBootApplication
public class GatewayMainApplication {public  static  void main(String[] args) {SpringApplication.run(GatewayMainApplication.class,args);}
}

运行并打开nocos:

(三)路由

1. 规则配置

新建路由规则文件application-route.yml:

spring:cloud:gateway:routes:- id: order-route  #路由规则id,自定义,唯一uri: lb://service-order  #路由目标微服务,lb代表负载均衡predicates:  #路由断言,判断请求是否符合规则,符合则路由到目标- Path=/api/order/**  #以请求路径做判断- id: products-routeuri: lb://service-productspredicates:- Path=/api/products/**#id表示路由的名字
#uri表示把请求转到哪
#predicates表示路由的匹配规则
#-Path表示路径为api/order/开头的都转给uri

让application.yml包含该文件:

spring:profiles:include: routeapplication:name: gatewaycloud:nacos:server-addr: 127.0.0.1:8848server:port: 80

在OrderController类上加上@RequestMapping("/api/order")

在ProductController类上加上@RequestMapping("/api/products")

在ProductFeignClient类的getProductById的注解改为@GetMapping("/api/products/product/{id}")

浏览器访问http://localhost/api/order/writeDb:

2.原理

3. 断言

长短写法:

spring:cloud:gateway:routes:- id: order-routeuri: lb://service-orderpredicates:     #长断言- name: Pathargs:patterns: /api/order/**match-trailing-slash: true- id: products-route  uri: lb://service-productspredicates:     #短断言- Path=/api/products/**

(四)过滤器

1.路径重写

这样就不用在控制层写@RequestMapping()了

spring:cloud:gateway:routes:- id: order-routeuri: lb://service-orderpredicates:- name: Pathargs:patterns: /api/order/**match-trailing-slash: truefilters:- RewritePath=/api/order/(?<segment>.*), /$\{segment}- id: products-routeuri: lb://service-productspredicates:- Path=/api/products/**filters:- RewritePath=/api/products/(?<segment>.*), /$\{segment}

2.默认fliter

spring:cloud:gateway:default-filters: #默认filters,如果其他没有设置就使用这个- AddResponseHeader=X-Response-Abc,123

3.全局过滤器

新建RtGlobalFilter类做全局过滤器

@Component
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String uri = request.getURI().toString();long start=System.currentTimeMillis();log.info("请求:"+uri+" 开始时间:"+start);//---------以上是前置逻辑--------------//Mono<Void> filter=chain.filter(exchange).doFinally((result)->{//----------以下是后置逻辑-------//long end=System.currentTimeMillis();log.info("请求"+uri+" 结束时间:"+end+" 耗时"+(end-start));});//放行return filter;}@Overridepublic int getOrder() {return 0;}
}

这样控制台就可以输出每个请求的路径和耗时时间

4. 全局跨域

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':allowed-origins: "*"allowed-headers: "*"allowed-methods: "*"

六. Seata-分布式事务

(一)架构原理 

下载Seata:Seata Java Download | Apache Seata

2.1.0版本下载后解压并进入bin目录,使用cmd输入seata-server.bat

访问http://localhost:7091/#/login进入页面,账号密码都是seata

在所有微服务模块引入:

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

每个微服务创建 file.conf ⽂件:

service {#transaction service group mappingvgroupMapping.default_tx_group = "default"#only support when registry.type=file, please don't set multiple addressesdefault.grouplist = "127.0.0.1:8091"#degrade, current not supportenableDegrade = false#disable seatadisableGlobalTransaction = false
}

在最大的方法入口标注注解@GlobalTransactional就会实现报错所有数据回滚

(二) 二阶提交协议

(三)XA模式

设置XA模式:

(四)AT模式

设置AT模式:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94136.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94136.shtml
英文地址,请注明出处:http://en.pswp.cn/web/94136.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

集成算法学习笔记

一、集成算法简介1. 核心思想类比“多个专家综合判断优于单个专家”&#xff0c;通过构建并结合多个个体学习器&#xff0c;提升模型的泛化能力&#xff08;降低过拟合风险、提高预测准确性&#xff09;&#xff0c;完成复杂的学习任务。2. 个体学习器与结合模块个体学习器&…

让Chrome信任自签名证书

让Chrome信任自签名证书&#xff08;Unix系列OS&#xff09; 背景 想在本地测试自己写的基于HTTPS连接的Web应用&#xff0c;跑在3001端口。但使用Chrome浏览器访问https://localhost:3001时显示连接不安全。解决了但没解决 使用mkcert一键创建证书&#xff1a; mkcert localho…

[江科大库]基于 OpenMV 的矩形识别与 STM32 串口通信(电子设计大赛实用教程)

🎯 基于 OpenMV 的矩形识别与 STM32 串口通信(电子设计大赛实用教程) 一、前言 在本科生电子设计大赛中,经常会遇到图像识别相关的任务,例如: 识别 矩形框(如识别一个 A4 纸、黑色标记框等); 将识别结果传输到 STM32 单片机,用于后续控制(舵机、移动小车、机械臂…

人脸识别驱动的工厂人体属性检测与预警机制

人体属性检测&#xff1a;人脸识别智慧检测驱动的工厂管理革新&#xff08;所有图片均为真实项目案例&#xff09;在制造业数字化转型浪潮中&#xff0c;人体属性检测技术已成为破解传统工厂管理难题的核心工具。通过融合人脸识别智慧检测、目标检测算法与多模态数据分析&#…

数据工程师——ETL

ETL面试题01 一、基础概念与理论类 1. 请解释什么是 ETL?它在数据处理流程中扮演什么角色? 答:ETL就是数据抽取、转化、加载。目的是将分散的数据源集中在一起进行处理分析。 数据抽取:是指各种数据源中抽取数据,包括关系型数据库(MySQL、Oracle等)、日志文件、Exce…

Oracle APEX 经典报表中的Checkbox

目录 1. 建表&#xff06;投入测试数据 2. 经典报表做成 2-1. 画面布局如下​编辑 2-2. 报表使用的SQL 2-3. RS列的Heading设定 2-4. Function and Global Variable Declaration 2-5. Execute when Page Loads 2-6. Process 3. 运行效果​编辑 1. 建表&#xff06;投入…

Codeforces Round 1043 (Div.3)

比赛连接&#xff1a;Codeforces Round 1043 (Div.3) A. Homework 题目链接&#xff1a;A - Homework Vlad and Dima have been assigned a task in school for their English class. They were given two strings aaa and bbb and asked to append all characters from bbb …

GPS欺骗式干扰的产生

我们在GNSS抗干扰天线的选型、测试方法以及为什么不能做RTK&#xff1f;&#xff08;抗干扰内容全集&#xff09;中提到的抗干扰天线&#xff0c;针对的是GPS压制式干扰。对于GPS欺骗式干扰&#xff0c;抗干扰天线是无能为力的。 简单来说&#xff0c;压制式干扰是通过发射强功…

[PV]AXI R/W/RW带宽计算的tcl脚本

AXI R/W/RW带宽计算的tcl脚本 我基于前述的axi_read_bw_per_id.tcl脚本进行了修改,使其支持: 读通道(Read Channel):计算基于rvalid && rready的有效周期(已在前述实现)。 写通道(Write Channel):计算基于wvalid && wready的有效周期,考虑wstrb的ac…

阿里云AnalyticDB同步数据至华为云taurusdb

1 概述 AnalyticDB和taurusdb都是高度兼容mysql协议的数据库&#xff0c;从现有的AnalyticDB官方数据同步方案来看&#xff0c;只有FlinkSQL合适。 同步方案官方文档&#xff1a; https://help.aliyun.com/zh/analyticdb/analyticdb-for-mysql/user-guide/flink-subscribes-b…

学习嵌入式之驱动——系统移植(二)

一、uboot常用命令与环境变量1.命令&#xff1a;&#xff08;1&#xff09;环境变量操作命令命令功能格式printenv 查看环境变量printenvsetenv新建/修改环境变量setenv 环境变量名 环境变量值saveenv保存环境变量saveenv&#xff08;2&#xff09;内存操作命令命令功能格式示例…

EasyExcel 合并单元格最佳实践:基于注解的自动合并与样式控制

EasyExcel 合并单元格最佳实践&#xff1a;基于注解的自动合并与样式控制 前言 在日常开发中&#xff0c;我们经常需要导出 Excel 报表&#xff0c;而合并单元格是提升报表可读性的常见需求。本文将介绍如何基于 EasyExcel 实现智能的单元格合并功能&#xff0c;通过自定义注解…

Unity设置UI显示区域

系列文章目录 untiy工具 文章目录 系列文章目录 👉前言 👉一、效果图 👉二、制作过程(检测中心点位置) 👉2-1、代码实现 👉三、优化为检测整个UI四个角点 👉四、性能优化建议 👉壁纸分享 👉总结 👉前言 思路: 获取屏幕的宽度和高度,定义中间区域的范围…

Qt中用于图像缩放的核⼼⽅法QPixmap::scaled

QPixmap::scaled是Qt中用于图像缩放的核⼼⽅法&#xff0c;其作⽤和⽤法如下&#xff1a;‌一、核心作用‌‌图像尺寸调整‌根据指定尺寸对图像进⾏等⽐例或⾮等⽐例缩放&#xff0c;⽀持放⼤和缩⼩操作。‌保持宽高比‌通过AspectRatioMode参数控制是否保持原始图像的宽⾼⽐。…

SQL Workbench/J:一款免费开源、跨平台的通用SQL查询工具

SQL Workbench/J 是一款基于 Java 开发的免费开源、跨平台的通用 SQL 查询工具。 SQL Workbench/J 主要专注于 SQL 脚本开发和数据导入导出功能&#xff0c;不提供各种数据库管理功能。 功能特性 跨平台&#xff1a;可以在任何安装了 Java 运行时环境的操作系统上运行&#xf…

DOLO 上涨:Berachain 生态爆发的前奏?

在 Berachain 生态逐渐进入公众视野之际&#xff0c;Dolomite&#xff08;简称 Dolomite&#xff0c;代币 DOLO&#xff09;成为链上表现最为突出的明星协议。其代币价格在短短两个月内&#xff0c;从 $0.03 飙升至 $0.3&#xff0c;涨幅接近 10 倍。市场不仅将其视作 Berachai…

吉利汽车与芯鼎微成立联合创新实验室共谱车规级LCoS显示新篇章

2025年8月20日&#xff0c;吉利汽车研究院技术规划中心副主任李莉、光学实验室负责人李金桦博士等一行四人莅临芯鼎微&#xff0c;双方共同为"吉利汽车-芯鼎微联合创新实验室"揭牌&#xff0c;标志着两家企业在车载先进显示技术领域迈入深度协同创新的新阶段。 在这汽…

NPM组件 @angular_devkit/core 等窃取主机敏感信息

【高危】NPM组件 angular_devkit/core 等窃取主机敏感信息 漏洞描述 当用户安装受影响版本的 angular_devkit/core 等NPM组件包时会窃取用户的主机名、用户名、IP地址信息并发送到攻击者可控的服务器地址。 MPS编号MPS-1jf5-s6ix处置建议强烈建议修复发现时间2025-08-14投毒…

docker cuda版安装 dockercuda版安装

目录 1.一键安装docker 测试ok 2.安装cuda支持 通用的应该没问题 安装工具包 配置 runtime&#xff1a; 3.检查 Docker 是否支持 NVIDIA 运行时 1.一键安装docker 测试ok curl -fsSL https://get.docker.com | sh 2.安装cuda支持 通用的应该没问题 也可以搜索安装 cuda版d…

Spring发布订阅模式详解

Spring 的发布订阅模式&#xff08;Publish-Subscribe Pattern&#xff09;是一种基于事件驱动的设计模式&#xff0c;通过 "事件" 作为中间载体实现组件间的解耦。在这种模式中&#xff0c;"发布者"&#xff08;Publisher&#xff09;负责产生事件并发布&…