SpringCloud學習筆記

個人學習進度:視頻跟敲+筆記(12天)

學習視頻:尚硅谷微服務速通(7小時左右課程)

資源:

1.pdf:微服務pdf(課程):https://pan.baidu.com/s/1g_TAuBjQ9Dw6WU7b7lwvCA?pwd=yyds?

2.語雀筆記(尚硅谷速通):尚硅谷 · 語雀

3.nacos面板地址:

  • http://192.168.43.71:8848/nacos/index.html

alt+enter:快捷鍵的使用(智能提示!!!)

測試接口:http://localhost:8000/create?userId=1&productId=100

一.微服務概念(名詞了解)

SpringCloud微服務架構中,常見的概念和名詞通過具體的技術棧得以實現和解決實際問題。

微服務架構風格,就像是把一個單獨的應用程序開發為一套小服務,每個小服務運行在自己進程中,并使用輕量級機制通信,通常是 HTTP API。

簡而言之:拒絕大型單體應用,基于業務邊界進行服務微化拆分,各個服務獨立部署運行。

1.微服務架構

微服務架構是將應用程序分解為一組小型、獨立服務的開發方法。在SpringCloud中,每個服務可以獨立開發、部署和擴展,它們通過輕量級通信協議(如HTTP RESTful API)進行交互。

場景理解:微服務架構是一種將應用程序分解為一組小型、獨立服務的開發方法。每個服務專注于特定的業務功能,并且可以獨立開發、部署和擴展。就像一家大型餐廳,有負責烹飪的廚師團隊(后端服務)、負責接待客人的服務員團隊(前端服務)、負責食材采購的采購團隊(數據訪問服務)等,每個團隊獨立運作但又相互協作,共同為顧客(用戶)提供完整的用餐體驗(應用程序功能)。

實現與解決:通過SpringBoot可以快速創建獨立運行的服務,SpringCloud則提供了服務之間的通信、發現等基礎設施支持,使得服務能夠相互協作完成復雜的業務功能。

Spring Cloud 系列

  • 官網:Spring Cloud
  • 遠程調用:OpenFeign
  • 網關:Gateway

Spring Cloud Alibaba 系列

  • 官網:https://sca.aliyun.com/
  • 注冊中心/配置中心:Nacos
  • 服務保護:Sentinel
  • 分布式事務:Seata

2.服務注冊與發現

是微服務架構中用于服務實例注冊、存儲及查詢定位,以便服務間通信協作的關鍵機制。

3.配置中心

集中管理應用配置信息,支持動態調整配置,實現配置與代碼分離,便于統一管理。

4.API網關

作為微服務架構的統一入口,負責路由、鑒權、限流等任務,簡化服務調用。

5.服務熔斷器

當服務調用失敗率高時,熔斷依賴服務調用鏈路,避免故障擴散,保障系統穩定。

6.服務降級

在系統故障或資源不足時,優先保障核心業務,降低非核心服務的質量或可用性。

7.分布式事務

確保分布式系統中多個服務的一系列操作要么全部成功,要么全部回滾,維持數據一致性。

8.服務監控與追蹤

實時監控微服務運行狀態和性能指標,追蹤服務調用鏈路,便于及時發現和解決問題。

9. 實際示例(步驟)

假設我們要構建一個電商系統,包含用戶服務、訂單服務和庫存服務:

1. 服務注冊與發現:每個服務在啟動時向Nacos注冊,其他服務通過Nacos發現并調用。

2. 配置管理:所有服務的配置信息(如數據庫連接)存儲在Nacos中,服務啟動時從Nacos獲取配置。

3. API網關:使用SpringCloud Gateway作為系統入口,處理用戶請求的路由、認證和限流。

4. 服務熔斷與降級:在訂單服務調用支付服務時,若支付服務出現故障,使用Resilience4j熔斷調用,并返回降級提示給用戶。

5. 分布式事務:在下單流程中,涉及訂單服務、庫存服務和支付服務的數據庫操作,使用Seata保證分布式事務的一致性。

6. 服務監控與追蹤:通過SpringCloud Sleuth和Zipkin記錄服務調用鏈路和性能指標,便于后續分析和優化。

10.微服務配圖

二.Nacos配置(注冊中心)

1.項目搭建

第一步:下載nacos

  • 下載軟件包:📎nacos-server-2.4.3.zip
  • 啟動控制面板:startup.cmd -m standalone
  • 打開地址:http://localhost:8848/nacos/index.html

第二步:創建SpringBoot項目

SpringBoot版本:3.3.4

項目名稱:cloud,根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><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.4</version><relativePath/> <!-- lookup parent from repository --></parent><modules><module>services</module></modules><modelVersion>4.0.0</modelVersion><groupId>com.weiyan</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version><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></project>

創建services:

下面有兩個子模塊:service-order(訂單服務)和service-product(商品服務)

第三步:引入公共依賴

services的pom中引入公共依賴,刷新:

<!--    導入公共依賴--><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>

services中的兩個子模塊分別引入web和test依賴:

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

maven如下所示,按組查看:

第四步:編寫配置文件和主類

配置文件名:application.properties

 # 服務名稱
spring.application.name=service-order
# 服務端口
server.port=8000
# nacos注冊中心地址
spring.cloud.nacos.server-addr=127.0.0.1:8848

主類:@SpringBootApplication注解

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

第五步:查看服務啟動

啟動其中一個服務后,查看nacos的控制面板:

  • http://192.168.43.71:8848/nacos/index.html

先打開nacos的目錄文件,bin目錄下,cmd命令彈窗,啟動:startup.cmd -m standalone

如下所示:

OK,項目搭建完成

2.demo1(集群服務)

第一步:打開services

右擊鼠標,賦值一個新的服務,需要修改配置

第二步:修改配置和端口

項目名稱修改,可以在后面加上數字,如:-2

需要修改選項(Modify Option):Program argument

輸入新的端口號:(自定義)

--server.port=8001

第三步:全選執行

ctrl+鼠標全選服務,run,運行:

運行成功,打開nacos面板(期間彈窗不關閉):http://localhost:8848/nacos/index.html

第四步:添加主類服務注解(必須的)

@EnableDiscoveryClient // 開啟服務注冊發現功能,需要重新啟動服務
@SpringBootApplication
public class ProductMainApplication {public static void main(String[] args) {SpringApplication.run(ProductMainApplication.class, args);}
}

開啟服務注冊發現功能后,可以運行下面測試類:ServiceInstance為服務實例

@SpringBootTest
public class DiscoveryTest {//標準注冊中心api(通用)@AutowiredDiscoveryClient discoveryClient;//nacos注冊中心api@AutowiredNacosServiceDiscovery nacosServiceDiscovery;@Testvoid nacosServiceDiscoveryTest() throws NacosException {for (String service : nacosServiceDiscovery.getServices()) {//微服務名稱System.out.println("service = " + service);//獲取ip+port(每個微服務名稱下有幾個端口)List<ServiceInstance> instances = nacosServiceDiscovery.getInstances(service);for (ServiceInstance instance : instances) {//主機地址+端口號System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}}@Testvoid discoveryClientTest(){for (String service : discoveryClient.getServices()) {//微服務名稱System.out.println("service = " + service);//獲取ip+port(每個微服務名稱下有幾個端口)List<ServiceInstance> instances = discoveryClient.getInstances(service);for (ServiceInstance instance : instances) {//主機地址+端口號System.out.println("ip:"+instance.getHost()+";"+"port = " + instance.getPort());}}}
}

運行結果如下:

3.demo2(遠程調用)

功能實現:(簡單示例)

1.一個訂單下有多個商品,這里以一個商品為例

2.訂單遠程調用商品模塊數據,計算的出總金額

3.遠程查詢訂單商品列表

數據公共模塊(model)

所有微服務的數據模型要公共使用,創建一個公共模塊model,數據在bean目錄下:

//可以使用@Data注解
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope>
</dependency>

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

在services的模塊下的pom文件中;導入model模塊的使用:

<dependency><groupId>com.weiyan</groupId><artifactId>model</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

業務代碼實現:

配置文件config:

RestTemplate 是 Spring 框架中提供的一個用于簡化 HTTP 請求和處理響應的工具類。[遠程調用]

@Configuration
public class ProductServiceConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

@Configuration
public class OrderServiceConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

service接口層

public interface ProductService{Product getProductById(Long productId);
}
public interface OrderService {//  根據用戶id和商品id,創建購物清單Order cresteOrder(Long productId,Long userId);
}

sevice的實現層(impl)

@Service
public class ProductServiceImpl  implements ProductService {@Overridepublic Product getProductById(Long productId){Product product = new Product();product.setId(productId);//設置默認值product.setProductName("蘋果-"+productId);product.setPrice(new BigDecimal("99"));product.setNum(2);return product;}
}
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@Overridepublic Order cresteOrder(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.setAddress("北京");order.setNickName("張三");order.setUserId(userId);//遠程查詢商品列表order.setProductList(Arrays.asList(product));return order;}//獲取遠程調用的商品數據private Product getProductFromRemote(Long productId){//1.獲取所有商品服務所在的所有機器IP+port(獲取實例)List<ServiceInstance> instances = discoveryClient.getInstances("service-product");//2.獲取實例,遠程調用一個url地址ServiceInstance instance = instances.get(0);String url = "http://"+instance.getHost() + ":" + instance.getPort()+"/product/"+productId;log.info("遠程請求:{}",url);//3.給遠程發送請求RestTemplate(),線程安全的。url返回的json數據自動轉換為class對象Product product = restTemplate.getForObject(url, Product.class);return product;}
}

Controller層

@RestController
public class ProductController {@AutowiredProductService productService;//根據商品id,查詢商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId){Product product =productService.getProductById(productId);return product;}
}
@RestController
public class OrderController {@AutowiredOrderService orderService;//創建訂單,商品id+用戶id@GetMapping("/create")public Order createOrder(@RequestParam("productId") Long productId,@RequestParam("userId") Long userId){Order order =orderService.cresteOrder(productId,userId);return order;}
}

測試結果:

這里默認設置商品數量為2,價格99,id和商品名稱動態變化

商品服務:http://localhost:9002/product/4

訂單服務:http://localhost:8000/create?userId=2&productId=100

{"id": 4,"price": 99,"productName": "蘋果-4","num": 2
}

{"id": 1,"totalAmount": 198,"userId": 2,"nickName": "張三","address": "北京","productList": [{"id": 100,"price": 99,"productName": "蘋果-100","num": 2}]
}

日志信息:

@Slf4j注釋,使用{}占位符(使用了):log.info("遠程請求:{}", url)

示例:log.info("用戶 {} 訪問了 {} 頁面", userId, pageUrl);

結果如下:

停掉其中一個服務后,依舊可以運行:(遠程請求端口變了)

缺陷:每次固定發給第一個服務端口,除非宕機了

改進:實現負載均衡,每次請求分別發給不同的服務端口(均衡)

4.demo3(負載均衡)

方法一:choose方法

依賴導入:

<!-- 負載均衡 -->
<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><scope>test</scope>
</dependency>

測試類:

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

改進方法:

//上面引入@AutowiredLoadBalancerClient loadBalancerClient;
//負載均衡獲取遠程調用的商品數據private Product getProductFromRemoteWithLoadBalance(Long productId){ServiceInstance instance = loadBalancerClient.choose("service-product");String url = "http://"+instance.getHost() + ":" + instance.getPort()+"/product/"+productId;log.info("遠程請求:{}",url);//3.給遠程發送請求RestTemplate(),線程安全的。url返回的json數據自動轉換為class對象Product product = restTemplate.getForObject(url, Product.class);return product;}

多次請求,刷新界面后,日志的遠程請求地址變了:

方法二:注解實現

RestTemplate 是 Spring 框架中提供的一個用于簡化 HTTP 請求和處理響應的工具類。

添加注解實現負載均衡: @LoadBalanced

@Configuration
public class OrderServiceConfig {@LoadBalanced  //注解式實現負載均衡@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
 private Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId){//這里ip地址直接寫成對方微服務的名字,會動態替換String url = "http://service-product/product/"+productId;log.info("遠程請求:{}",url);//restTemplate在請求發送前:動態將service-product負載均衡的替換成一個IP地址Product product = restTemplate.getForObject(url, Product.class);return product;}

因為restTemplate動態替換了,也不知道想誰發送了請求,在商品控制層輸出,hello打招呼:

這里8000日志輸出,ip地址被隱藏了,動態替換。不知道向誰發出的遠程請求。

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

一共遠程請求了5次,9000和9001分別兩次,9002請求一次。(如下所示)

5.配置中心

一.基本使用

依賴引入:

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

配置文件:

# 指定配置中心地址
spring.cloud.nacos.server-addr=localhost:8848
spring.config.import=nacos:service-order.properties

Naco控制面板,添加配置:

重啟項目:controller層添加:

@Value("${order.timeout}")
String orderTimeout;
@Value("${order.auto-confirm}")
String orderAutoConfirm;//接口
@GetMapping("/config")
public String config(){return "order.timeout="+orderTimeout+" order.auto-confirm="+orderAutoConfirm;
}

運行項目,調用接口:

如果其他服務模塊沒有使用配置中心,添加配置:

# 禁用導入檢查(配置中心)
spring.cloud.nacos.config.import-check.enabled=false

二.動態刷新

第一種方法:

controller層添加注解:@RefreshScope

修改配置:

接口數據頁自動刷新:

第二種方法(推薦):

ConfigurationProperties

創建包:Properties,存放采用配置,統一管理

@Component
//配置批量綁定在nacos下,可以無需@RefreshScope就能實現自動刷新(前綴)
@ConfigurationProperties(prefix = "order") 
@Data
public class OrderProperties {String timeout;String autoConfirm;
//    String dbUrl;
}

修改控制層:

//@RefreshScope  //自動刷新
@RestController
public class OrderController {@AutowiredOrderService orderService;//    @Value("${order.timeout}")
//    String orderTimeout;
//    @Value("${order.auto-confirm}")
//    String orderAutoConfirm;@AutowiredOrderProperties orderProperties;@GetMapping("/config")public String config(){return "order.timeout="+orderProperties.getTimeout()+"; " +"order.auto-confirm="+orderProperties.getAutoConfirm() +";";}//創建訂單,商品id+用戶id@GetMapping("/create")public Order createOrder(@RequestParam("productId") Long productId,@RequestParam("userId") Long userId){Order order =orderService.cresteOrder(productId,userId);return order;}
}

三.配置監聽

啟動類添加:

	@BeanApplicationRunner applicationRunner(NacosConfigManager manager){return args -> {ConfigService configService = manager.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 = " + configInfo);}});};}

四.數據隔離

用名稱空間來區分多套環境:

首先,創建不同命名空間:(四個)

在不同命名空間下,設置配置,其中分組來區分微服務(每個組就是一個微服務):

order.timeout=1min
order.auto-confirm=1h

依次完成配置和操作,開始克隆:

server:port: 8000
spring:
#  激活環境profiles:active: devapplication:name: service-ordercloud:nacos:server-addr: 127.0.0.1:8848config:
#        導入檢查禁用import-check:enabled: false# 動態取值,看當前激活環境,默認為devnamespace: ${spring.profiles.active:dev}#同一個文件中定義多個獨立的配置塊,使用---
---
# 導入不同空間下的order組的配置文件
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: test---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: prod---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: dev

6.Nacos經典面試題

一.注冊中心宕機

二.配置項優先級

以配置中心的數據為準,在項目中優先級低(規則如下:)

小結:

三.OpenFeign(遠程調用)

1.基本介紹

OpenFeign 是一個聲明式遠程調用客戶端;通過注解方式更加便捷。

上面使用的編程式遠程調用請求:RestTemplate(自己手動);這里聲明式:OpenFeign(注解)

2.基本使用

其中mvc注解兩套使用邏輯:

1.標注在controller上,是接受這樣的請求

2.標注在feignClient上,是發生這樣的請求

實現功能:

1.引入依賴:

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

2.主類中添加注解:@EnableFeignClients //開啟Feign遠程調用功能

3.創建feign包,創建接口:自動連接注冊中心,負載均衡的挑選一個

@FeignClient(value = "service-product")  //feign客戶端+遠程微服務名
public interface ProductFeignClient {//    其中mvc注解兩套使用邏輯:
//        1.標注在controller上,是接受這樣的請求
//        2.標注在feignClient上,是發生這樣的請求@GetMapping("/product/{id}")Product getProductById(@PathVariable("id") Long id);
}

4.修改OrderServiceimpl中代碼:

   //引入OpenFeignClient@AutowiredProductFeignClient productFeignClient;@Overridepublic Order cresteOrder(Long productId, Long userId) {//從遠程獲取一個商品數據(示例:模擬只有一個商品)//  Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);//  改用openfeign注解遠程調用Product product = productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);//總金額:商品的金額*商品購買的數量order.setTotalAmount(  product.getPrice().multiply(new BigDecimal(product.getNum())));order.setAddress("北京");order.setNickName("張三");order.setUserId(userId);//遠程查詢商品列表order.setProductList(Arrays.asList(product));return order;}

5.測試結果:同樣實現遠程調用,而且實現了負載均衡使用

兩次

一次

3.遠程調用技巧

1.遠程使用第三方api:指定url地址[墨跡天氣為例]

2.調用業務api(自己 編寫):直接復制對方的controller簽名

4.進階配置

一.開啟日志

yml文件配置:

logging:level:# 監控日志包名(整個包),級別debug,記錄詳細記錄com.atguigu.order.feign: debug

config容器中配置:feign下的logger

@Configuration
public class OrderServiceConfig {// 創建RestTemplate實例, 放到容器中并返回(線程安全)@LoadBalanced  //注解式實現負載均衡@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}//日志注解@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
}

二.超時控制

connectTimeout:連接超時

readTimeout:讀取超時{業務處理時間}

默認配置如下所示:讀取60s,連接10s

訂單impl設置睡眠時間:目的,延遲創建訂單的業務處理時間100s

 //設置連接時間:100秒try{TimeUnit.SECONDS.sleep(100);}catch (InterruptedException e){throw new RuntimeException(e);}

調用接口,創建訂單:http://localhost:8000/create?userId=1&productId=100

在超時前已一直加載轉圈:

時間到了之后,返回500錯誤:讀取超時

控制臺輸出:超時信息

三.超時配置

訂單order的配置文件,添加一個application-feign.yml;并在yml中調用激活:

#  激活環境profiles:active: test
# 激活環境標識include: feign
spring:cloud:openfeign:client:config:# 客戶端名稱(其中default默認配置)default:logger-level: fullconnect-timeout: 1000read-timeout: 2000service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000

添加這個配置后,5s后就有返回結果:500

四.重試機制

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

可以查看重試默認配置:5次,請求失敗了也會重新請求,最多5次,每次間隔100ms

時間間隔=超時+延遲等待(100ms*1.5)

   public Default() {this(100L, TimeUnit.SECONDS.toMillis(1L), 5);}

使用結果測試:http://localhost:8000/create?userId=1&productId=100

五.攔截器

應用:上游放共享數據,下游可以收到(全局有效)

@Component
public class XTokenRequestInterceptor implements RequestInterceptor {/*** 請求攔截器* @param requestTemplate 請求模版**/@Overridepublic void apply(RequestTemplate requestTemplate) {requestTemplate.header("X-Token", UUID.randomUUID().toString());}
}

控制層:測試輸出

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

結果(先注釋之前的超時控制):http://localhost:8000/create?userId=1&productId=100

六.Fallback兜底返回

引入依賴:sentinel

        <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency>
@FeignClient(value = "service-product",fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {@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.注釋掉上面的重傳機制和超時設置

2.停掉商品的服務

3.開啟熔斷:

feign:sentinel:enabled: true

返回結果:

當商品服務開啟時:

5.經典面試題

客服端負載均衡與服務端負載均衡的區別:

四.Sentinel(服務保護)

1.基本使用

常用功能:服務保護,限流,熔斷降級

官網:home | Sentinel

wiki:https://github.com/alibaba/Sentinel/wiki

下載控制臺:📎sentinel-dashboard-1.8.8.jar

啟動命令:java -jar sentinel-dashboard-1.8.8.jar

訪問面板:http://localhost:8080/#/login

1.1依賴和配置:

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

其中order的feign的yml配置

spring:cloud:sentinel:transport:dashboard: localhost:8080eager: true   # 默認懶加載,這里改為一開始就啟動

product的配置:

spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true

1.2面板和流控測試

測試接口:http://localhost:8000/create?userId=1&productId=100

添加注解:OrderServiceImpl下的創建方法添加:@SentinelResource(value = "createOrder")

測試:每秒創建一個,多了報錯。

快速刷新請求,出現默認錯誤:

2.異常處理

2.1自定義BlockException異常

自定義返回的json對象: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;}
}

編寫自定義異常:

@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {private ObjectMapper objectMapper = new ObjectMapper();@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response,String resourceName, BlockException e) throws Exception {// response.setStatus(429); //too many requests,這里//這里把對象轉換為json格式的范湖類型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();}
}

重啟項目,重新配置sentinel的限流,多次刷新后:設置create限流

若如果添加的createOrder限流,多次刷新,出現:

原因:只給資源起了名,沒有標注blockhander和fallback,異常沒人管,直接回調Springboot的異常

(設置全局異常可以處理)

2.2blockHandler(指定兜底回調)

對createOrder限流,多次刷新

 @SentinelResource(value = "createOrder",blockHandler = "createOrderFallback")@Overridepublic Order createOrder(Long productId, Long userId) {
//        Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);//使用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;}

顯示流控異常:

2.3OpenFeign - 兜底回調

對GET:http://service-product/product/{id}添加流量控制

默認會調用之前寫好的兜底回調:

3.流控規則

3.1 開啟集群

示例:均攤閾值設置為5,每個集群有三個微服務。

單擊均攤:表示每個微服務可以每秒5次請求

總體閾值:表示三個微服務1秒一共5次請求

3.2流控模式

(1)默認:直接+快速失敗(如上)

(2)鏈路:控流B,限制C,示例:秒殺場景

spring:cloud:sentinel:transport:dashboard: localhost:8080eager: trueweb-context-unify: false  #先關閉統一的上下文

秒殺接口:

@GetMapping("/kill")public Order killOrder(@RequestParam("productId") Long productId,@RequestParam("userId") Long userId){Order order =orderService.cresteOrder(productId,userId);order.setId(Long.MAX_VALUE);return order;}

這種方式,斷開鏈路,僅對某一個鏈路生效

(3)關聯模式:寫優先策略

接口:

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

正常讀接口沒有問題,但當寫接口1s內請求過多時,讀接口被限制住了

開兩個窗口測試:(系統內出現資源競爭時,使用關聯策略)

3.3流控效果[直接模式]

3.3.1快速失敗

orderController添加日志注解@SLf4j

   @GetMapping("/writeDb")public String writeDb(){return "writeDb";}@GetMapping("/readDb")public String readDb(){log.info("readDb");   //日志打印return "readDb";}
// 異常處理首先設置狀態碼response.setStatus(429); //too many requests

重啟項目,添加鏈路規則,限流1

使用apipost進行壓力測試:并發數10次,進行5秒

設置后置斷言,成功為200,失敗設置了狀態碼為429

開始測試:

3.3.2 預熱/冷啟動

慢慢啟動,直到到達峰值

這個設置表示,3秒內,逐漸達到峰值10,一開始默認為三分之一處,3個請求。

3.3.3均速排隊

其其中QPS數量不能大于1000,默認單位為ms

隊排不上,會被拋棄;底層使用漏桶算法。

4.熔斷規則

熔斷時間到了之后,半開狀態,有探測數據進行探測

1.測試:修改商品服務接口,故意休眠2秒

  //根據商品id,查詢商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id") Long productId, HttpServletRequest request){String header = request.getHeader("X-Token");System.out.println("hello...token="+header);Product product =productService.getProductById(productId);//休眠2秒try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}return product;}

2.太慢了,會使用兜底回調,30s內熔斷了。5s內先進行熔斷檢測,統計5s內的前五個請求的異常比例

3.可知,30s后會處于半開狀態,當商品服務正常使用,不慢時,又可以正常使用了。(超時注釋掉)

5.熱點參數

可以限流對象,不再是資源級別,而是精細到參數級別,對于請求方法的某一個參數進行限制。

應用:

1.商城中的秒殺下單,用戶id需要限制。[防止機器人,瘋狂下單]

2.用戶id為vip,不限流QPS

3商品666是下架商品,需要限流

需要,先自定義資源,不可以和請求方法重名:@SentinelResource注解

資源名稱為seckill-order,對它進行熱點規則限流

 @GetMapping("/seckill")@SentinelResource(value = "seckill-order",fallback = "seckillFallback")public Order seckill(@RequestParam(value = "userId",required = false) Long userId,@RequestParam(value = "productId",defaultValue = "1000") Long productId){Order order = orderService.createOrder(productId, userId);order.setId(Long.MAX_VALUE);return order;}public Order seckillFallback(Long userId,Long productId, BlockException exception){System.out.println("seckillFallback....");Order order = new Order();order.setId(productId);order.setUserId(userId);order.setAddress("異常信息:"+exception.getClass());return order;}

測試:http://localhost:8000/seckill?userId=1&productId=100

1.設置熱點規則,每個參數0[用戶ID],無論id是幾,每秒用戶id只能創建一個訂單

攜帶用戶id限流空,不帶用戶id不限流

2.用戶6為VIP,不限制QPS請求

3.商品666號為下架商品,不允許訪問(限制第二個參數)

4.將上面的 BlockException改為Throwable

可以處理所有異常,使用兜底回調,返回兜底回調,而不是500報錯界面

項目重啟后,sentinel設置的規則都失效了。sentinel沒有對這些規則實現持久化,需要結合nacos,配置好后,然后連接數據庫中,實現規則的持久化。

五.GateWay(網關)

官網:Spring Cloud Gateway

1.基本配置(路由)

創建對應模塊,引入依賴:

    <dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><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.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency></dependencies>

配置文件application.yml:

spring:profiles:include: routeapplication:name: gatewaycloud:nacos:server-addr: 127.0.0.1:8848# localhost/api/order
server:port: 80

路由規則:

spring:cloud:gateway:routes:- id: order-routeuri: lb://service-orderpredicates:- Path=/api/order/**- id: order-routeuri: lb://service-productpredicates:- Path=/api/product/**   

啟動服務:

http://localhost/api/order/readDb

2.斷言

參數(個數/類型)

作用

After

1/datetime

在指定時間之后

Before

1/datetime

在指定時間之前

Between

2/datetime

在指定時間區間內

Cookie

2/string,regexp

包含cookie名且必須匹配指定值

Header

2/string,regexp

包含請求頭且必須匹配指定值

Host

N/string

請求host必須是指定枚舉值

Method

N/string

請求方式必須是指定枚舉值

Path

2/List<String>,bool

請求路徑滿足規則,是否匹配最后的/

Query

2/string,regexp

包含指定請求參數

RemoteAddr

1/List<String>

請求來源于指定網絡域(CIDR寫法)

Weight

2/string,int

按指定權重負載均衡

XForwardedRemoteAddr

1/List<string>

從X-Forwarded-For請求頭中解析請求來源,并判斷是否來源于指定網絡域

測試:

spring:cloud:gateway:routes:- id: bing-routeuri: https://www.baidu.com/predicates:- name: Pathargs:patterns: /s- name: Queryargs:param: wdregexp: haha- name: Vipargs:param: uservalue: leifengyangorder: 10metadata:hello: world- id: order-routeuri: lb://service-orderpredicates:- name: Pathargs:patterns: /api/order/**matchTrailingSlash: trueorder: 1- id: product-routeuri: lb://service-productpredicates:- name: Pathargs:patterns: /api/product/**order: 1

編寫一個自定義的路由斷言工廠:

@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {public VipRoutePredicateFactory() {super(Config.class);}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {// localhost/s?wd=haha&user=leifengyangServerHttpRequest request = serverWebExchange.getRequest();String first = request.getQueryParams().getFirst(config.param);return StringUtils.hasText(first) && first.equals(config.value);}};}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("param", "value");}/*** 可以配置的參數*/@Validatedpublic static class Config {@NotEmptyprivate String param;@NotEmptyprivate String value;public @NotEmpty String getParam() {return param;}public void setParam(@NotEmpty String param) {this.param = param;}public @NotEmpty String getValue() {return value;}public void setValue(@NotEmpty String value) {this.value = value;}}
}

必須要指定參數和用戶才可以!

3.過濾器

參數(個數/類型)

作用

AddRequestHeader

2/string

添加請求頭

AddRequestHeadersIfNotPresent

1/List<string>

如果沒有則添加請求頭,key:value方式

AddRequestParameter

2/string、string

添加請求參數

AddResponseHeader

2/string、string

添加響應頭

CircuitBreaker

1/string

僅支持forward:/inCaseOfFailureUseThis方式進行熔斷

CacheRequestBody

1/string

緩存請求體

DedupeResponseHeader

1/string

移除重復響應頭,多個用空格分割

FallbackHeaders

1/string

設置Fallback頭

JsonToGrpc

請求體Json轉為gRPC

LocalResponseCache

2/string

響應數據本地緩存

MapRequestHeader

2/string

把某個請求頭名字變為另一個名字

ModifyRequestBody

僅 Java 代碼方式

修改請求體

ModifyResponseBody

僅 Java 代碼方式

修改響應體

PrefixPath

1/string

自動添加請求前綴路徑

PreserveHostHeader

0

保護Host頭

RedirectTo

3/string

重定向到指定位置

RemoveJsonAttributesResponseBody

1/string

移除響應體中的某些Json字段,多個用,分割

RemoveRequestHeader

1/string

移除請求頭

RemoveRequestParameter

1/string

移除請求參數

RemoveResponseHeader

1/string

移除響應頭

RequestHeaderSize

2/string

設置請求大小,超出則響應431狀態碼

RequestRateLimiter

1/string

請求限流

RewriteLocationResponseHeader

4/string

重寫Location響應頭

RewritePath

2/string

路徑重寫

RewriteRequestParameter

2/string

請求參數重寫

RewriteResponseHeader

3/string

響應頭重寫

SaveSession

0

session保存,配合spring-session框架

SecureHeaders

0

安全頭設置

SetPath

1/string

路徑修改

SetRequestHeader

2/string

請求頭修改

SetResponseHeader

2/string

響應頭修改

SetStatus

1/int

設置響應狀態碼

StripPrefix

1/int

路徑層級拆除

Retry

7/string

請求重試設置

RequestSize

1/string

請求大小限定

SetRequestHostHeader

1/string

設置Host請求頭

TokenRelay

1/string

OAuth2的token轉發

1.網關會將原路徑原封不動的轉過去,在網關向下轉的時候,進行路徑重寫。

2.使用過濾器,路徑重寫:(使用通義靈碼解析,會有就行,正則表達式)

3.注釋掉之前的路徑,重啟項目

spring:cloud:gateway:routes:- id: bing-routeuri: https://www.baidu.com/predicates:- name: Pathargs:patterns: /s- name: Queryargs:param: wdregexp: haha- name: Vipargs:param: uservalue: leifengyangorder: 10metadata:hello: world- id: order-routeuri: lb://service-orderpredicates:- name: Pathargs:patterns: /api/order/**matchTrailingSlash: truefilters: #將/api/order/ab/c  轉換為/ab/c- RewritePath=/api/order/?(?<segment>.*), /$\{segment}- OnceToken=X-Response-Token, jwtorder: 1- id: product-routeuri: lb://service-productpredicates:- name: Pathargs:patterns: /api/product/**filters:- RewritePath=/api/product/?(?<segment>.*), /$\{segment}order: 1

4.配置默認過濾器

      default-filters:- AddResponseHeader=X-Response-Abc, 123

5.全局過濾器

@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("請求【{}】結束:時間:{},耗時:{}ms",uri,end,end-start);}); //放行   10sreturn filter;}@Overridepublic int getOrder() {return 0;}
}

4.微服務跨域(允許跨域)

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

六.Seata(分布式事務)---了解使用

1.基礎環境

建表:

CREATE DATABASE IF NOT EXISTS `storage_db`;
USE  `storage_db`;
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (`id` int(11) NOT NULL AUTO_INCREMENT,`commodity_code` varchar(255) DEFAULT NULL,`count` int(11) DEFAULT 0,PRIMARY KEY (`id`),UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO storage_tbl (commodity_code, count) VALUES ('P0001', 100);
INSERT INTO storage_tbl (commodity_code, count) VALUES ('B1234', 10);-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE DATABASE IF NOT EXISTS `order_db`;
USE  `order_db`;
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) DEFAULT NULL,`commodity_code` varchar(255) DEFAULT NULL,`count` int(11) DEFAULT 0,`money` int(11) DEFAULT 0,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;CREATE DATABASE IF NOT EXISTS `account_db`;
USE  `account_db`;
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_id` varchar(255) DEFAULT NULL,`money` int(11) DEFAULT 0,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO account_tbl (user_id, money) VALUES ('1', 10000);
-- 注意此處0.3.0+ 增加唯一索引 ux_undo_log
DROP TABLE IF EXISTS `undo_log`;
CREATE TABLE `undo_log` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`branch_id` bigint(20) NOT NULL,`xid` varchar(100) NOT NULL,`context` varchar(128) NOT NULL,`rollback_info` longblob NOT NULL,`log_status` int(11) NOT NULL,`log_created` datetime NOT NULL,`log_modified` datetime NOT NULL,`ext` varchar(100) DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

接口測試:

2.遠程鏈路

  1. 下載seata

📎apache-seata-2.1.0-incubating-bin.tar.gz

  1. 解壓并啟動:seata-server.bat

http://127.0.0.1:7091

導入依賴:

<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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78756.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78756.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78756.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【大模型】Coze AI 智能體工作流從配置到使用實戰詳解

目錄 一、前言 二、工作流介紹 2.1 什么是工作流 2.2 工作流與對話流 2.2.1 兩者區別 2.3 工作流節點介紹 2.3.1 工作流節點說明 2.3.2 開始節點與結束節點 2.4 工作流入口 2.4.1 自定義智能體入口 2.4.2 從資源庫新增工作流 2.5 工作流使用限制 三、工作流配置與使…

Discord多賬號注冊登錄:如何同時管理多個賬戶?

Discord是許多人、特別是游戲玩家和社區管理者的重要溝通工具。隨著用戶需求的增長&#xff0c;越來越多的人開始在Discord上注冊多個賬號進行管理。例如&#xff0c;個人和工作賬號的區分&#xff0c;多個游戲社區的參與&#xff0c;或者通過不同的身份進行更靈活的社交互動。…

前端如何使用Mock模擬數據實現前后端并行開發,提升項目整體效率

1. 安裝 Mock.js npm install mockjs --save-dev # 或使用 CDN <script src"https://cdn.bootcdn.net/ajax/libs/Mock.js/1.0.0/mock-min.js"></script>2. 創建 Mock 數據文件 在項目中新建 mock 目錄&#xff0c;創建 mock.js 文件&#xff1a; // m…

AimRT 從零到一:官方示例精講 —— 二、HelloWorld示例.md

HelloWorld示例 官方倉庫&#xff1a;helloworld 配置文件&#xff08;configuration_helloworld.yaml? &#xff09; 依據官方示例項目結構自行編寫YAML配置文件 # 基礎信息 base_info:project_name: helloworld # 項目名稱build_mode_tags: ["EXAMPLE", &quo…

Tauri 跨平臺開發指南及實戰:用前端技術征服桌面應用(合集-萬字長文)

厭倦了笨重的Electron應用&#xff1f;想要構建體積小、性能高、安全可靠的跨平臺桌面應用&#xff1f;Tauri將是你的不二之選&#xff01;本教程帶你從入門到精通&#xff0c;掌握這個下一代桌面應用開發框架&#xff0c;并通過實戰APK分析工具項目&#xff0c;將理論知識轉化…

【LeetCode 熱題 100】矩陣置零 / 螺旋矩陣 / 旋轉圖像 / 搜索二維矩陣 II

??個人主頁&#xff1a;小羊 ??所屬專欄&#xff1a;LeetCode 熱題 100 很榮幸您能閱讀我的文章&#xff0c;誠請評論指點&#xff0c;歡迎歡迎 ~ 目錄 矩陣矩陣置零螺旋矩陣旋轉圖像搜索二維矩陣 II 矩陣 矩陣置零 矩陣置零 用兩個數組分別標記行和列&#xff0c;判斷…

JavaScript進階(三十一): === 與 == 比較運算符

文章目錄 一、前言二、嚴格相等運算符 ()三、寬松相等運算符 ()四、推薦做法五、特殊情況 一、前言 在 JavaScript 中&#xff0c; 和 都是比較運算符&#xff0c;但它們在比較時有重要區別&#xff1a; 二、嚴格相等運算符 () 不進行類型轉換只有當兩個操作數的值和類型都…

HTML與安全性:XSS、防御與最佳實踐

HTML 與安全性&#xff1a;XSS、防御與最佳實踐 前言 現代 Web 應用程序無處不在&#xff0c;而 HTML 作為其基礎結構&#xff0c;承載著巨大的安全責任。跨站腳本攻擊&#xff08;XSS&#xff09;仍然是 OWASP Top 10 安全威脅之一&#xff0c;對用戶數據和網站完整性構成嚴…

安達發|破解醫療器械多BOM困局:APS生產計劃排產軟件解決方案

在醫療器械設備制造行業&#xff0c;生產計劃與排程&#xff08;Advanced Planning and Scheduling, APS&#xff09;系統的應用至關重要。由于醫療器械行業具有嚴格的法規要求&#xff08;如FDA、ISO 13485&#xff09;、復雜的多級BOM&#xff08;Bill of Materials&#xff…

組件輪播與樣式結構重用實驗

任務一&#xff1a;使用“Swiper 輪播組件”對自行選擇的圖片和文本素材分別進行輪播&#xff0c;且調整對應的“loop”、“autoPlay”“interval”、“vertical”屬性&#xff0c;實現不同的輪播效果&#xff0c;使用Swiper 樣式自定義&#xff0c;修改默認小圓點和被選中小圓…

【Stable Diffusion】文生圖進階指南:采樣器、噪聲調度與迭代步數的解析

在Stable Diffusion文生圖(Text-to-Image)的創作過程中,采樣器(Sampler)、噪聲調度器(Schedule type)和采樣迭代步數(Steps)是影響生成效果的核心參數。本文將從技術原理、參數優化到實踐應用,深入剖析DPM++ 2M采樣器、Automatic噪聲調度器以及采樣步數的設計邏輯與協…

第一天 車聯網定義、發展歷程與生態體系

前言 車聯網&#xff08;Internet of Vehicles, IoV&#xff09;作為物聯網&#xff08;IoT&#xff09;在汽車領域的延伸&#xff0c;正在徹底改變人們的出行方式。無論是自動駕駛、遠程診斷&#xff0c;還是實時交通優化&#xff0c;車聯網技術都扮演著核心角色。本文將從零…

foc控制 - clarke變換和park變換

1. foc控制框圖 下圖是foc控制框圖&#xff0c;本文主要是講解foc控制中的larke變換和park變換clarke變換將 靜止的 a b c abc abc坐標系 變換到 靜止的 α β αβ αβ坐標系&#xff0c;本質上還是以 定子 為基準的坐標系park變換 則將 α β αβ αβ坐標系 變換到 隨 轉…

軟件系統容量管理:反模式剖析與模式應用

在數字化時代&#xff0c;軟件系統的重要性日益凸顯。隨著業務的不斷拓展和用戶數量的持續增長&#xff0c;軟件系統的容量管理成為保障其高效運行的關鍵因素。《發布&#xff01;軟件的設計與部署》第二部分圍繞容量展開深入探討&#xff0c;系統地闡述了容量的定義、范圍&…

23種設計模式-行為型模式之解釋器模式(Java版本)

Java 解釋器模式&#xff08;Interpreter Pattern&#xff09;詳解 &#x1f9e0; 什么是解釋器模式&#xff1f; 解釋器模式是一種行為型設計模式&#xff0c;主要用于解釋和執行語言的語法規則。它定義了一個解釋器來處理特定的語言句法&#xff0c;并通過一個抽象語法樹來…

基于Springboot + vue + 爬蟲實現的高考志愿智能推薦系統

項目描述 本系統包含管理員和學生兩個角色。 管理員角色&#xff1a; 個人中心管理&#xff1a;管理員可以管理自己的個人信息。 高校信息管理&#xff1a;管理員可以查詢、添加或刪除高校信息&#xff0c;并查看高校詳細信息。 學生管理&#xff1a;管理員可以查詢、添加或…

五種機器學習方法深度比較與案例實現(以手寫數字識別為例)

正如人們有各種各樣的學習方法一樣&#xff0c;機器學習也有多種學習方法。若按學習時所用的方法進行分類&#xff0c;則機器學習可分為機械式學習、指導式學習、示例學習、類比學習、解釋學習等。這是溫斯頓在1977年提出的一種分類方法。 有關機器學習的基本概念&#xff0c;…

Blender插件 三維人物角色動作自動綁定 Auto-Rig Pro V3.68.44 + Quick Rig V1.26.16

Auto-Rig Pro是一個集角色綁定、動畫重定向和Unity、Unreal Engine的Fbx導出于一體的全能解決方案。最初作為我個人的內部角色綁定工具開發&#xff0c;我幾年前將其發布&#xff0c;并自那時起增加了許多新功能。 Blender插件介紹 Auto-Rig Pro插件簡介 Auto-Rig Pro是一個強…

網絡基礎概念:從菜鳥到入門

前言&#xff1a;快遞小哥的故事 想象一下你要給朋友寄個禮物&#xff0c;這個過程其實和網絡通信非常相似&#xff1a; 1. 你需要知道朋友的”地址“&#xff08;IP地址&#xff09; 2. 要注明是送到他家大門還是物業代收&#xff08;端口號&#xff09; 3. 要選擇快遞公司并…

23種設計模式-行為型模式之中介者模式(Java版本)

Java 中介者模式&#xff08;Mediator Pattern&#xff09;詳解 &#x1f9e0; 什么是中介者模式&#xff1f; 中介者模式是一種行為型設計模式&#xff0c;它通過定義一個中介者對象來封裝一組對象之間的交互。中介者使得各個對象不需要顯式地知道彼此之間的關系&#xff0c…