springCloud特色知识记录(基于黑马教程2024年)

server/2025/1/13 12:19:51/

目录

Nacos 简介

Nacos 的特点

Nacos 的使用步骤可以查看黑马教程文档:‍‌​‌​⁠​⁠​​​​​‬​​​​‍‌‬⁠​​‬​​​​‍​⁠​​​⁠​​‬​⁠​​day03-微服务01 - 飞书云文档 (feishu.cn)

OpenFeign 的使用步骤

Feign Logger.Level 的选项

网关 

自定义过滤器(拦截器) 

网关到微服务的用户传递 

META-INF是什么?

微服务之间的用户传递

配置管理 

 如何进行配置管理?

如果进行热部署更新? 

更新路由

微服务保护和分布式管理

雪崩问题

sentinel是什么?

如何使用sentinel?

熔断的具体实现步骤

主要逻辑

如何解决雪崩问题

分布式事务(多个服务或数据库之间数据一致性的问题)

​编辑

什么事seata?

XA模式 

AT模式 


Nacos 简介

Nacos 是阿里巴巴开源的一个动态服务发现、配置管理和服务管理平台。它在微服务架构中常被用作服务注册中心和配置中心。

Nacos 的特点
  1. 服务发现与注册:支持 DNS 和 HTTP 协议的服务发现。
  2. 动态配置管理:支持实时动态配置刷新。
Nacos 的使用步骤可以查看黑马教程文档:‍‌​‌​⁠​⁠​​​​​‬​​​​‍‌‬⁠​​‬​​​​‍​⁠​​​⁠​​‬​⁠​​day03-微服务01 - 飞书云文档 (feishu.cn)

通常Nacos会和OpenFeign结合使用 更加方便

OpenFeign的产生就是为了让远程调用像本地方法调用一样简单。

使用步骤:

1.引入服务注册和服务发现的依赖

<!--nacos 服务注册发现-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--nacos 服务注册发现-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

2. 配置Nacos地址

spring:cloud:nacos:server-addr: 自己的虚拟机Ip:8848

OpenFeign 的使用步骤

  1. 引入依赖

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

  2.  开启 Feign 功能 在主类上添加 @EnableFeignClients 注解。

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

  3. 定义 Feign 客户端 使用 @FeignClient 注解标注接口,指定调用的服务名称。

    @FeignClient(name = "service-name")
    public interface MyFeignClient {@GetMapping("/api/endpoint")String getEndpoint();
    }
    

  4. 调用 Feign 接口 注入定义的 Feign 接口并调用方法。

    @RestController
    public class MyController {@Autowiredprivate MyFeignClient myFeignClient;@GetMapping("/call")public String callService() {return myFeignClient.getEndpoint();}
    }
    

    如果将这个代理的专门使用一个包提取出来,那么我们需要在启动类上面添加扫描包的注解

package com.hmall.pay;import com.hmall.api.config.DefaultFeignConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@MapperScan("com.hmall.pay.mapper")
@SpringBootApplication
@EnableFeignClients(basePackages =  "com.hmall.api.client" ,defaultConfiguration = DefaultFeignConfig.class)
public class PayApplication
{public static void main(String[] args) {SpringApplication.run(PayApplication.class, args);}
}

在 Spring Boot 的微服务项目中,上述代码配置了 defaultConfiguration 属性来指定一个默认的配置类 DefaultFeignConfig,它用于 Feign 客户端的默认行为设置。具体来说,这是为了增强日志打印功能,方便开发者在调用微服务时追踪和调试。

以下是DefaultFeignConfig的内容:

package com.hmall.api.config;import feign.Logger;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig
{@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}
}
Feign Logger.Level 的选项
  • NONE:不记录任何日志(默认值)。
  • BASIC:记录请求方法、URL、响应状态码以及执行时间。
  • HEADERS:在 BASIC 的基础上,记录请求和响应的头信息。
  • FULL:记录请求和响应的所有信息,包括头、体、元数据。

网关 

服务拆分之后面临两大问题:

1.服务地址过多,前端不知道如何请求谁

2. 每个服务都可以需要登录信息

自定义过滤器(拦截器) 

 NettyRoutingFilter 是 Spring Cloud Gateway 中的一个核心过滤器,它负责将请求真正路由到目标服务,并处理响应的回传。简单来说,这是网关在处理请求时,实际完成路由和转发的核心组件

网关到微服务的用户传递 

网关层的请求拦截: 在微服务架构中,为了提高安全性和请求处理的一致性,需要在网关层对所有请求进行统一拦截。具体要求如下:

  • 放行无需登录的请求:对于公共接口或资源,不进行Token校验,直接放行。
  • 拦截需要登录的请求:对于需要登录的请求,检查Request中是否包含有效的Token。
    • 如果Token不存在或无效,返回HTTP状态码401 (UNAUTHORIZED),表示用户未登录,并终止请求的后续处理(调用response.setComplete())。
    • 如果Token有效,解析Token获取用户的唯一标识(如用户ID),将该用户ID通过ServerWebExchange注入到请求头中,然后继续放行请求。
 String id = userId.toString();ServerWebExchange swe = exchange.mutate().request(build -> build.header("user-info", id)).build();

微服务中如何获取用户ID: 通常情况下,微服务可以通过读取请求头中的user-info字段获取用户ID。然而,如果每个微服务都单独实现一个拦截器,会导致代码重复、不便于维护。

为了解决这个问题,可以将通用的拦截器逻辑抽取到common模块。所有微服务都引入common模块,直接复用其中的拦截器。这种方式可以避免重复开发,提高代码的复用性和一致性。但是这个时候springBoot无法扫描到这个拦截器的包,因此拦截器不会失效。所以要配置spring.factories 文件

基于Spring Boot的拦截器配置: 微服务通常基于Spring Boot,而不是传统的Spring MVC。如果直接使用Spring MVC的拦截器,在Spring Boot环境下可能会报错。

总结:为了解决上述问题,可以通过在common模块中为拦截器配置META-INF文件,同时在拦截器类上添加@ConditionalOnClass(DispatcherServlet.class)注解。这样可以确保拦截器仅在支持Spring MVC的环境中加载,从而避免不兼容问题。

META-INF是什么?

META-INF 是Java程序的一个特殊目录,用于存放配置文件和元数据信息。它通常位于JAR文件的根目录下,主要包含以下类型的内容:

  1. MANIFEST.MF 文件

    • Java的清单文件,用于描述JAR包的信息。
    • 包括主类、版本号、依赖项等。
  2. Spring Boot相关配置

    • 例如,spring.factories 文件,用于注册自动配置类。
    • 格式为键值对,可以定义拦截器、过滤器等组件的自动加载逻辑。
  3. 服务注册文件

    • 用于SPI(服务提供接口)机制,例如META-INF/services目录下的文件定义了特定接口的实现类。

示例:在common模块中的spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.hmall.common.config.MyBatisConfig,\com.hmall.common.config.JsonConfig,\com.hmall.common.config.MvcConfig

微服务之间的用户传递

如果是微服务之间的用户Id传递的话,其实获取到的用户id的值是null,因为微服务之间的网络请求不是通过网关的,所以网关无法在请求头中设置userId,其他服务也不可以获取到userId的值了

微服务之间是通过openFeign进行网络请求转发的,在转发之前我们是可以获得用户Id的,所以我们可以在请求发送之前设置拦截器,如果我们在每一个微服务都加一个拦截器太麻烦了。所以我们选择加在专门写FeignClient的模块中(hm-api)

那么我们应该如何改造转发的请求呢?在转发之前我们是可以获取到用户id的,所以我们可以借助Feign中提供的一个拦截器接口:feign.RequestInterceptor

public interface RequestInterceptor {/*** Called for every request. * Add data using methods on the supplied {@link RequestTemplate}.*/void apply(RequestTemplate template);
}

我们只需要实现这个接口,然后实现apply方法,利用RequestTemplate类来添加请求头,将用户信息保存到请求头中。这样以来,每次OpenFeign发起请求的时候都会调用该方法,传递用户信息。

package com.hmall.api.config;import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig
{@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}@Beanpublic RequestInterceptor userInfoRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate requestTemplate) {// 获取用户IdLong user = UserContext.getUser();if(user == null) {// 如果为空则直接跳过return;}// 存入请求头当中requestTemplate.header("user-info",user.toString());}};}}
  • 网关部分:用户身份校验,并将用户信息存入请求头。
  • 微服务部分:使用拦截器提取用户信息存入 ThreadLocal,微服务间通过 OpenFeign 的 RequestInterceptor 传递用户信息。

配置管理 

在微服务架构中,服务数量众多且配置管理复杂,常常导致重复代码和维护成本增加。通过 Nacos 的配置管理功能,我们能够实现配置的统一管理和动态更新,提升开发效率并减少运维压力。

在微服务架构中,每个服务都需要独立管理自己的配置文件,例如数据库连接(JDBC)、日志配置、Swagger 接口文档配置等。这些配置中往往存在大量重复内容,既增加了维护成本,也容易引发配置不一致问题。
Nacos 是一款集服务注册与配置管理于一体的工具,通过将公共配置提取到 Nacos 中并实现动态加载,可以有效减少代码冗余、降低维护难度并支持配置实时更新。

 如何进行配置管理?

引入 Maven 依赖

在 Spring Boot 项目中,添加以下依赖:

  <!--nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>

2. 在Nacos网址上面添加配置,分别提取jdbc-mysql配置,swagger配置,日志的配置

jdbc共享配置: 

spring:datasource:url: jdbc:mysql://${hm.db.host:192.168.88.130}:${hm.db.port:3306}/${hm.db.database}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true&autoReconnect=true&failOverReadOnly=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: ${hm.db.un:root}password: ${hm.db.pw:123}
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto

 日志的共享配置:

logging:level:com.hmall: debugpattern:dateformat: HH:mm:ss:SSSfile:path: "logs/${spring.application.name}"

 swagger的共享配置:

knife4j:enable: trueopenapi:title: ${hm.swagger.title:"黑马商城购物车接口文档"}description: ${hm.swagger.desc:"黑马商城购物车接口文档"}email: zhanghuyi@itcast.cnconcat: 虎哥url: https://www.itcast.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- com.hmall.cart.controller- ${hm.swagger.package}

3. 创建bootstrap.yaml 公共配置是动态的,所以我们需要在 bootstrap.yaml进行配置

必须配置其 spring: application: name,profiles: active: ,cloud:nacos:config:extension

spring:application:name: cart-service # 服务名称profiles:active: devcloud:nacos:server-addr: 192.168.88.130 # nacos地址config:file-extension: yaml # 文件后缀名shared-configs: # 共享配置- dataId: shared-jdbc.yml # 共享mybatis配置- dataId: shared-log.yml # 共享日志配置- dataId: shared-swagger.yml # 共享日志配置

注意这里的shared-configs的dataId的配置名一定要和Nacos里面的一模一样 ,如果 dataId 与 Nacos 中的配置名称不一致,服务将无法加载到对应的共享配置,从而导致启动失败或无法正确读取配置

4. 剩余部分就需要在application.yaml里面配置

server:port: 8082
feign:okhttp:enabled: true # 开启OKHttp连接池支持
hm:swagger:title: 购物车服务接口文档package: com.hmall.cart.controllerdb:host: 192.168.88.130 # 修改为你自己的虚拟机IP地址database: hm-cart
如果进行热部署更新? 

进入Nacos网站http://192.168.88.130:8848/nacos 开始添加配置

使用默认的 应用名称.yaml(例如,cart-service.yaml),这样无需显式在 bootstrap.yaml 中指定 dataId 

什么是默认的?

应用名称作为默认 Data ID
Spring Boot 项目的 spring.application.name 属性会作为 Nacos 配置的默认 Data ID

例如: 如果你的 bootstrap.yaml 配置如下:

spring:application:name: cart-servicecloud:nacos:server-addr: 192.168.88.130:8848

那么 Nacos 会自动尝试加载以下文件作为配置: 

Data ID: cart-service.yaml
Group: DEFAULT_GROUP
  • 优先加载的文件格式
    默认情况下,Nacos 会加载和 spring.cloud.nacos.config.file-extension 对应的文件格式(默认为 yaml)。

  • 无需显式指定 Data ID
    只要 Nacos 配置文件的 Data IDspring.application.name 一致(并以 .yaml 作为后缀),就会被自动加载,而无需手动在 bootstrap.yaml 中声明 shared-configs 或特定 dataId

配置项前缀匹配prefix 指定的值必须在配置文件中明确存在。例如,hm.cart 对应的配置项必须是以下形式之一:

  • 在对应的yml 中,配置如下,
    hm:cart:maxAmount: 10
    

 此时对应的配置类的注解@ConfigurationProperties(prefix = "hm.cart")的prefix必须是hm.cart

package com.hmall.cart.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "hm.cart")
public class CartProperties {private Integer maxAmount;
}

更新路由

微服务保护和分布式管理

雪崩问题

 
sentinel是什么?

Sentinel 是阿里巴巴开源的一款用于分布式系统的流量控制和熔断降级的中间件。它主要用于保护微服务的稳定性,帮助应对高并发场景下的流量突增或服务调用异常。

Sentinel 提供了灵活的流量控制规则和强大的监控能力,是 Spring Cloud Alibaba 技术栈中的核心组件之一,用于服务治理和高可用保障。

如何使用sentinel?

1. 引入依赖

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

2. 连接sentinel-dashboard控制台,需要配置控制台,修改application.yaml文件,添加下面内容:

spring:cloud: sentinel:transport:dashboard: localhost:8090

3. 由于我们的SpringMVC接口是按照Restful风格设计,因此购物车的查询、删除、修改等接口全部都是/carts路径,所以我们需要在application.yaml里面添加 http-method-specify: true # 开启请求方式前缀

spring:cloud:sentinel:transport:dashboard: 127.0.0.1:8090http-method-specify: true # 开启请求方式前缀

‌‍‬‍‌​​​​​​⁠​​​⁠​‍‍​​⁠‍​​‍​​​​⁠⁠‬​⁠​​‬​‌‌​‍​‬​‬详细请点击黑马教程:day05-服务保护和分布式事务 - 飞书云文档 (feishu.cn)

接下来详细介绍一下熔断的解决办法

熔断的具体实现步骤

步骤 1:配置 Sentinel 的熔断规则

Sentinel 可视化控制台 中配置熔断规则,基于:

  • 异常比例(当调用失败率超过设定值时触发)。
  • 异常数(当调用失败总数超过设定值时触发)。
  • 响应时间(当接口响应时间超过设定值时触发)。

示例:

  • 熔断条件:某接口失败率 >50% 且调用量 >10,在 1 分钟内触发熔断。
  • 熔断恢复:在熔断 5 秒后恢复尝试。

步骤 2:编写 FallbackFactory

当服务触发熔断时,FallbackFactory 提供降级逻辑。正常会去调用ItemClient接口,但是当ItemClinet接口对应的Controller的处理出现异常或者请求被限流了,就会走这个fallback”备选方案“,它也会创建一个ItemClient,去返回一些提示信息。以 ItemClientFactoryFallback 为例:

主要逻辑
  1. 实现 FallbackFactory 接口。
  2. create 方法中捕获异常信息 Throwable
  3. 定义服务降级逻辑:
    • 非关键业务返回默认值(如返回空集合)。
    • 关键业务抛出业务异常,触发事务回滚,确保数据一致性。

代码解读

package com.hmall.api.fallback;import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import com.hmall.common.exception.BizIllegalException;
import com.hmall.common.utils.CollUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;import java.util.Collection;
import java.util.List;@Slf4j
public class ItemClientFactoryFallback implements FallbackFactory<ItemClient> {@Overridepublic ItemClient create(Throwable cause) {return new ItemClient() {@Overridepublic List<ItemDTO> queryItemByIds(Collection<Long> ids) {log.error("远程调用ItemClient#queryItemByIds方法出现异常,参数:{}", ids, cause);// 查询购物车允许失败,查询失败,返回空集合return CollUtils.emptyList();}@Overridepublic void deductStock(List<OrderDetailDTO> items) {// 库存扣减业务需要触发事务回滚,查询失败,抛出异常throw new BizIllegalException(cause);}};}
}

步骤 3:在配置类中注册为 Bean

原因

  • 默认情况下,Spring Boot 不会扫描非显式标注为 @Component 的类。
  • 需要显式将 FallbackFactory 注册为 Bean,才能生效。

代码解读

DefaultFeignConfig 配置类中:

  1. 注册 ItemClientFactoryFallback

package com.hmall.api.config;import com.hmall.api.fallback.ItemClientFactoryFallback;
import com.hmall.common.utils.UserContext;
import feign.Logger;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
public class DefaultFeignConfig
{@Beanpublic Logger.Level feignLoggerLevel(){return Logger.Level.FULL;}@Beanpublic RequestInterceptor userInfoRequestInterceptor(){return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate requestTemplate) {// 获取用户IdLong user = UserContext.getUser();if(user == null) {// 如果为空则直接跳过return;}// 存入请求头当中requestTemplate.header("user-info",user.toString());}};}// 注册为Bean@Beanpublic ItemClientFactoryFallback itemClientFallbackFactory(){return new ItemClientFactoryFallback();}}

步骤 4:在服务接口中绑定降级逻辑

使用 @FeignClient 注解绑定服务,并指定:

  • value:目标微服务名称。
  • fallbackFactory:对应的 FallbackFactory 类。
  • configuration:自定义的 Feign 配置类。

代码解读

@FeignClient(value = "item-service",fallbackFactory = ItemClientFactoryFallback.class,configuration = DefaultFeignConfig.class
)
public interface ItemClient {@GetMapping("/items")List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);@PostMapping("/stock/deduct")void deductStock(@RequestBody List<OrderDetailDTO> items);
}

如何解决雪崩问题

  1. 快速失败

    • 熔断器在触发后立即返回降级结果,避免资源被耗尽。
  2. 默认降级逻辑

    • 通过 FallbackFactory 提供兜底逻辑,为非关键业务返回默认值,降低错误扩散的影响。
  3. 保护核心业务

    • 关键业务如库存扣减,触发异常并回滚,确保数据一致性。
  4. 监控与恢复

    • Sentinel 自动监控系统恢复状态,当异常比例降低时自动关闭熔断器,恢复正常调用。

分布式事务(多个服务或数据库之间数据一致性的问题)

‍‌‌​​​‍​​​​​​⁠‍​⁠​‬​‍‬⁠​​​​​‬​⁠​‌​‌‍⁠‬​‬⁠​​​‍day05-服务保护和分布式事务 - 飞书云文档 (feishu.cn)

什么事seata?

Seata(Simple Extensible Autonomous Transaction Architecture)是阿里巴巴开源的一款分布式事务解决方案。它为分布式系统中的事务一致性问题提供了简单、高效的解决方案,支持多种事务模型,帮助开发者轻松实现分布式事务。

在微服务架构中,各服务通常独立部署,拥有独立的数据库。这种设计虽然带来了高可用性和扩展性,但也引入了分布式事务问题(如跨服务的数据一致性)。Seata 专注于保证事务的一致性。

XA模式 

首先我们可以在Nacos中的共享shared-seata.yaml配置文件中设置:

seata: data-source-proxy-mode: XA

然后我们要利用@GlobalTransactional标记分布式事务的入口方法即可

 

AT模式 

RabbitMQ 

详细查看请查看RabbitMQ高级篇-CSDN博客


http://www.ppmy.cn/server/158000.html

相关文章

计算机网络(三)——局域网和广域网

一、局域网 特点&#xff1a;覆盖较小的地理范围&#xff1b;具有较低的时延和误码率&#xff1b;使用双绞线、同轴电缆、光纤传输&#xff0c;传输效率高&#xff1b;局域网内各节点之间采用以帧为单位的数据传输&#xff1b;支持单播、广播和多播&#xff08;单播指点对点通信…

基于 Python 和 OpenCV 的人脸识别上课考勤管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Kafka 主题管理

主题作为消息的归类&#xff0c;分区则是对消息的二次归类。分区可以有一至多个副本&#xff0c;每个副本对应一个日志文件。 分区的划分不仅为Kafka提供了可伸缩性、水平扩展的功能&#xff0c;还通过多副本机制来为Kafka提供数据冗余以提高可靠性。 图 主题、分区、副本和日…

在 Java 中使用 GET 和 POST 请求

在 Java 中&#xff0c;我们通常使用 HttpURLConnection 或第三方库&#xff08;如 Apache HttpClient 或 OkHttp&#xff09;来发送 GET 和 POST 请求。本文将通过示例讲解如何实现这两种 HTTP 请求。 1. 使用 HttpURLConnection 实现 GET 和 POST 请求 HttpURLConnection 是…

26个开源Agent开发框架调研总结(2)

根据Markets & Markets的预测&#xff0c;到2030年&#xff0c;AI Agent的市场规模将从2024年的50亿美元激增至470亿美元&#xff0c;年均复合增长率为44.8%。 Gartner预计到2028年&#xff0c;至少15%的日常工作决策将由AI Agent自主完成&#xff0c;AI Agent在企业应用中…

02-51单片机数码管与矩阵键盘

一、数码管模块 1.数码管介绍 如图所示为一个数码管的结构图&#xff1a; 说明&#xff1a; 数码管上下各有五个引脚&#xff0c;其中上下中间的两个引脚是联通的&#xff0c;一般为数码管的公共端&#xff0c;分为共阴极或共阳极&#xff1b;其它八个引脚分别对应八个二极管…

【数据结构-堆】2233. K 次增加后的最大乘积

给你一个非负整数数组 nums 和一个整数 k 。每次操作&#xff0c;你可以选择 nums 中 任一 元素并将它 增加 1 。 请你返回 至多 k 次操作后&#xff0c;能得到的 nums的 最大乘积 。由于答案可能很大&#xff0c;请你将答案对 109 7 取余后返回。 示例 1&#xff1a; 输入&…

计算机网络 (32)用户数据报协议UDP

前言 用户数据报协议&#xff08;UDP&#xff0c;User Datagram Protocol&#xff09;是计算机网络中的一种重要传输层协议&#xff0c;它提供了无连接的、不可靠的、面向报文的通信服务。 一、基本概念 UDP协议位于传输层&#xff0c;介于应用层和网络层之间。它不像TCP那样提…