手把手帶你開發starter,點對點帶你講解原理

来源:https://www.cnblogs.com/Jcloud/archive/2023/01/03/17021527.html
-Advertisement-
Play Games

在2012 年 10 月,一個叫 Mike Youngstrom 的人在 Spring Jira 中創建了一個功能請求,要求在 Spring Framework 中支持無容器 Web 應用程式體繫結構,提出了在主容器引導 Spring 容器內配置 Web 容器服務;這件事情對 SpringBoot ... ...


京東物流 孔祥東

   _____            _             ____              _   
  / ____|          (_)           |  _ \            | |  
 | (___  _ __  _ __ _ _ __   __ _| |_) | ___   ___ | |_ 
  \___ \| '_ \| '__| | '_ \ / _` |  _ < / _ \ / _ \| __|
  ____) | |_) | |  | | | | | (_| | |_) | (_) | (_) | |_ 
 |_____/| .__/|_|  |_|_| |_|\__, |____/ \___/ \___/ \__|
        | |                  __/ |                      
        |_|                 |___/                       


1. 為什麼要用Starter?

  • 現在我們就來回憶一下,在還沒有Spring-boot框架的時候,我們使用Spring 開發項目,如果需要某一個框架,例如mybatis,我們的步驟一般都是:
  • 到maven倉庫去找需要引入的mybatis jar包,選取合適的版本(易發生衝突)
  • 到maven倉庫去找mybatis-spring整合的jar包,選取合適的版本(易發生衝突)
  • 在spring的applicationContext.xml文件中配置dataSource和mybatis相關信息
  • 假如所有工作都到位,一般可以一氣呵成;但很多時候都會花一堆時間解決jar 衝突,配置項缺失,導致怎麼都啟動不起來等等,各種問題。

所以在2012 年 10 月,一個叫 Mike Youngstrom 的人在 Spring Jira 中創建了一個功能請求,要求在 Spring Framework 中支持無容器 Web 應用程式體繫結構,提出了在主容器引導 Spring 容器內配置 Web 容器服務;這件事情對 SpringBoot 的誕生應該說是起到了一定的推動作用。

所以SpringBoot 設計的目標就是簡化繁瑣配置,快速建立Spring 應用。

  • 然後在開發Spring-boot 應用的是時候, 經常可以看到我們的pom 文件中引入了spring-boot-starter-web、spring-boot-starter-data-redis、mybatis-spring-boot-starter 這樣的依賴,然後幾乎不用任何配置就可以使用這些依賴的功能,真正的感受到了開箱即用的爽。
  • 下麵我們就先來嘗試自己開發一個Starter。

2. 命名規範

在使用spring-boot-starter,會發現,有的項目名稱是 XX-spring-boot-starter,有的是spring-boot-starter-XX,這個項目的名稱有什麼講究呢?從springboot官方文檔摘錄:

這段話的大概意思就是,麻煩大家遵守這個命名規範:

Srping官方命名格式為:spring-boot-starter-{name}

非Spring官方建議命名格式:{name}-spring-boot-starter

3. 開發示例

下麵我就以記錄日誌的一個組件為示例來講述開發一個starter 的過程。

3.1 新建工程

首先新建一個maven 工程,名稱定義為jd-log-spring-boot-starter

image.png

3.2 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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.13</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.jd</groupId>
<artifactId>jd-log-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
<name>jd-log-spring-boot-starter</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>


<dependencies>
<!-- 提供了自動裝配功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<!-- 在編譯時會自動收集配置類的條件,寫到一個META-INF/spring-autoconfigure-metadata.json中-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--記錄日誌會用到切麵,所以需要引入-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

這邊稍微解釋一下這幾個依賴:

spring-boot-autoconfigure :提供自動化裝配功能,是為了Spring Boot 應用在各個模塊提供自動化配置的作用;即加入對應 pom,就會有對應配置其作用;所以我們想要自動裝配功能,就需要引入這個依賴。

spring-boot-configuration-processor:將自定義的配置類生成配置元數據,所以在引用自定義STARTER的工程的YML文件中,給自定義配置初始化時,會有屬性名的提示;確保在使用@ConfigurationProperties註解時,可以優雅的讀取配置信息,引入該依賴後,IDEA不會出現“spring boot configuration annotation processor not configured”的錯誤;編譯之後會在META-INF 下生成一個spring-configuration-metadata.json 文件,大概內容就是定義的配置的元數據;效果如下截圖。

image.png

spring-boot-starter-aop :這個就不用解釋了,因為示例是記錄日誌,我們用到切麵的功能,所以需要引入。

3.3 定義屬性配置

/**
* @author kongxiangdong2
* @Title: LogProperties
* @ProjectName jd-log-spring-boot-starter
* @Description: TODO
* @date 2022/9/110:04
*/
@ConfigurationProperties(prefix = "jd")
@Data
public class LogProperties {


/**
* 是否開啟日誌
*/
private boolean enable;


/**
* 平臺:不同服務使用的區分,預設取 spring.application.name
*/
@Value("${spring.application.name:#{null}}")
private String platform;

@ConfigurationProperties:該註解和@Value 註解作用類似,用於獲取配置文件中屬性定義並綁定到Java Bean 或者屬性中;換句話來說就是將配置文件中的配置封裝到JAVA 實體對象,方便使用和管理。

這邊我們定義兩個屬性,一個是是否開啟日誌的開關,一個是標識平臺的名稱。

3.4 定義自動配置類

/**
* @author kongxiangdong2
* @Title: JdLogAutoConfiguration
* @ProjectName jd-log-spring-boot-starter
* @Description: TODO
* @date 2022/9/110:06
*/
@Configuration
@ComponentScan("com.jd")
@ConditionalOnProperty(prefix = "jd",name = "enable",havingValue = "true",matchIfMissing = false)
@EnableConfigurationProperties({LogProperties.class})
public class JdLogAutoConfiguration {


//
}

這個類最關鍵了,它是整個starter 最重要的類,它就是將配置自動裝載進spring-boot的;具體是怎麼實現的,下麵在講解原理的時候會再詳細說說,這裡先完成示例。

@Configuration :這個就是聲明這個類是一個配置類

@ConditionalOnProperty:作用是可以指定prefix.name 配置文件中的屬性值來判定configuration是否被註入到Spring,就拿上面代碼的來說,會根據配置文件中是否配置jd.enable 來判斷是否需要載入JdLogAutoConfiguration 類,如果配置文件中不存在或者配置的是等於false 都不會進行載入,如果配置成true 則會載入;指定了havingValue,要把配置項的值與havingValue對比,一致則載入Bean;配置文件缺少配置,但配置了matchIfMissing = true,載入Bean,否則不載入。

在這裡稍微擴展一下經常使用的Condition

註解 類型 說明
@ConditionalOnClass Class Conditions類條件註解 當前classpath下有指定類才載入
@ConditionalOnMissingClass Class Conditions類條件註解 當前classpath下無指定類才載入
@ConditionalOnBean Bean ConditionsBean條件註解 當期容器內有指定bean才載入
@ConditionalOnMissingBean Bean ConditionsBean條件註解 當期容器內無指定bean才載入
@ConditionalOnProperty Property Conditions環境變數條件註解(含配置文件) prefix 首碼name 名稱havingValue 用於匹配配置項值matchIfMissing 沒找指定配置項時的預設值
@ConditionalOnResource ResourceConditions 資源條件註解 有指定資源才載入
@ConditionalOnWebApplication Web Application Conditionsweb條件註解 是web才載入
@ConditionalOnNotWebApplication Web Application Conditionsweb條件註解 不是web才載入
@ConditionalOnExpression SpEL Expression Conditions 符合SpEL 表達式才載入

@EnableConfigurationProperties使@ConfigurationProperties 註解的類生效。

3.5 配置EnableAutoConfiguration

在resources/META-INF/ 目錄新建spring.factories 文件,配置內容如下;

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.jd.JdLogAutoConfiguration

好了,至此自定義Starter 大體框架已經好了,下麵就是我們記錄日誌的功能。

3.6 業務功能實現

首先我們先定義一個註解Jdlog

/**
* @author kongxiangdong2
* @Title: Jdlog
* @ProjectName jd-log-spring-boot-starter
* @Description: TODO
* @date 2022/9/110:04
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Jdlog {
}

定義切麵執行邏輯,這邊就簡單的列印一下配置文件的屬性值+目標執行方法+耗時。

import com.jd.annotation.Jdlog;
import com.jd.config.LogProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;


/**
* @author kongxiangdong2
* @Title: LogAspectjProcess
* @ProjectName jd-log-spring-boot-starter
* @Description: TODO
* @date 2022/9/111:12
*/
@Aspect
@Component
@Slf4j
@AllArgsConstructor
public class LogAspectjProcess {


LogProperties logProperties;


/**
* 定義切點
*/
@Pointcut("@annotation(com.jd.annotation.Jdlog)")
public void pointCut(){}


/**
* 環繞通知
*
* @param thisJoinPoint
* @param jdlog
* @return
*/
@Around("pointCut() && @annotation(jdlog)")
public Object around(ProceedingJoinPoint thisJoinPoint, Jdlog jdlog){


//執行方法名稱
String taskName = thisJoinPoint.getSignature()
.toString().substring(
thisJoinPoint.getSignature()
.toString().indexOf(" "),
thisJoinPoint.getSignature().toString().indexOf("("));
taskName = taskName.trim();
long time = System.currentTimeMillis();
Object result = null;
try {
result = thisJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
log.info("{} -- method:{} run :{} ms",logProperties.getPlatform(), taskName,
(System.currentTimeMillis() - time));
return result;



整體項目結構就是這樣子

image.png

好了,現在就可以打包編譯安裝

image.png

3.7 測試使用

然後就可以在其他項目中引入使用了;下麵以一個簡單的spring-boot web 項目做個測試,在pom 中引入下麵的依賴配置。

<dependency>
<groupId>com.jd</groupId>
<artifactId>jd-log-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

增加一個http 訪問的方法,標註上@Jdlog 註解

image.png

application.yaml 文件中配置

jd:
enable: true
platform: "測試項目"

啟動測試,訪問地址http://localhost:8080/test/method1,控制台列印如下:

image.png

咋樣,自定義的Starter是不是特別的簡單啊,快動手試試吧!

上面我們講的都是怎麼去開發一個starter,但是到底為什麼要這樣,spring-boot 是如何去實現的?是不是還不知道?那下麵我們就來說說;

代碼示例地址:https://coding.jd.com/kongxiangdong2/jd-log-spring-boot-starter.git

4. 原理講解

我們上面已經看到一個starter,只需要引入到pom 文件中,再配置一下(其實都可以不配置)jd.enable=true,就可以直接使用記錄日誌的功能了,Spring-boot 是怎麼做到的?

在開始的時候說過,Spring-boot 的好處就是可以自動裝配。那下麵我就來說說自動裝配的原理。

相比於傳統Spring 應用,我們搭建一個SpringBoot 應用,我們只需要引入一個註解(前提:引入springBoot y依賴)@SpringBootApplication,就可以直接運行;所以我們就從這個註解開始入手,看看這個註解到底做了寫什麼?

SpringBootApplication 註解

點開@SpringBootApplication註解可以看到包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan三個註解。

image.png

前面的四個註解就不用過多敘述了,是定義註解最基本的,關鍵在於後面的三個註解:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,其實也就是說在啟動類上如果不使用@SpringBootApplication 這個複合註解,直接使用者三個註解一樣可以達到相同的效果。

@SpringBootConfiguration 註解:我們再次點進去看這個註解,其實它就是一個@Configuration 註解。

image.png

@ComponentScan 註解

@ComponentScan 註解:配置包掃描定義的掃描路徑,把符合掃描規則的類裝配到spring容器

@EnableAutoConfiguration 註解

@EnableAutoConfiguration 打開自動裝配(自動配置著重來看該註解)

註解 作用 解釋
@SpringBootConfiguration 標記當前類為配置類 加上這個註解就是為了讓當前類作為一個配置類交由 Spring 的 IOC 容器進行管理,因為前面我們說了,SpringBoot 本質上還是 Spring,所以原屬於 Spring 的註解 @Configuration 在 SpringBoot 中也可以直接應用
@ComponentScan 配置包掃描定義的掃描路徑,把符合掃描規則的類裝配到spring容器 用於定義 Spring 的掃描路徑,等價於在 xml 文件中配置 context:component-scan,假如不配置掃描路徑,那麼 Spring 就會預設掃描當前類所在的包及其子包中的所有標註了 @Component,@Service,@Controller 等註解的類。
@EnableAutoConfiguration 打開自動裝配 下麵著重講解

我們再次點擊@EnableAutoConfiguration進入查看,它是一個由 @AutoConfigurationPackage 和 @Import 註解組成的複合註解;

image.png

首先我們先來看@Import 這個註解,這個是比較關鍵的一個註解;

在說這個註解之前我們先舉個例子,假如我們有一個類Demo,它是一個不在啟動配置類目錄之下的,也就意味著它不會被掃描到,Spring 也無法感知到它的存在,那麼如果需要能將它被掃描到,是不是我們可以通過加@Import 註解來導入Demo 類,類似如下代碼

@Configuration
@Import(Demo.class)
public class MyConfiguration {
}

所以,我們可以知道@Import 註解其實就是為了去導入一個類。所以這裡@Import({AutoConfigurationImportSelector.class}) 就是為了導入AutoConfigurationImportSelector 類,那我們繼續來看這個類,AutoConfigurationImportSelector實現的是DeferredImportSelector介面,這是一個延遲導入的類;再細看會有一個方法比較顯眼,根據註解元數據來選擇導入組件,當註解元數據空,直接返回一個空數組;否則就調用getAutoConfigurationEntry ,方法中會使用AutoConfigurationEntry的getConfigurations(),configurations是一個List<String>,那麼我們看下AutoConfigurationEntry是怎麼生成的。

image.png

進入到getAutoConfigurationEntry 方法中可以看到主要是getCandidateConfigurations 來獲取候選的 Bean,並將其存為一個集合;後續的方法都是在去重,校驗等一系列的操作。

image.png

我們繼續往getCandidateConfigurations 方法里看,最終通過SpringFactoriesLoader.loadFactoryNames來獲取最終的configurations,並且可以通過斷言發現會使用到META-INF/spring.factories文件,那麼我們再進入SpringFactoriesLoader.loadFactoryNames()中來看下最終的實現。

image.png

SpringFactoriesLoader.loadFactoryNames()方法會讀取META-INF/spring.factories文件下的內容到Map中,再結合傳入的factoryType=EnableAutoConfiguration.class,因此會拿到 org.springframework.boot.autoconfigure.EnableAutoConfiguration為key對應的各個XXAutoConfiguration的值,然後springboot在結合各個starter中的代碼完成對於XXAutoConfiguration中的Bean的載入動作。

image.png

image.png

這邊再擴展一下這個內容,通過 SpringFactoriesLoader 來讀取配置文件 spring.factories 中的配置文件的這種方式是一種 SPI 的思想。

@AutoConfigurationPackage 註解

進入這個註解看,其實它就是導入了Registrar 這個類

image.png

再進入這個類查看,它其實是一個內部類,看代碼的大概意思就是讀取到我們在最外層的 @SpringBootApplication 註解中配置的掃描路徑(沒有配置則預設當前包下),然後把掃描路徑下麵的Bean註冊到容器中;

image.png

總結

好了,現在我們大概來理一下整個自動裝配的流程:

  1. 啟動類中通過使用@SpringBootApplication實現自動裝配的功能;
  1. 實際註解@SpringBootApplication是藉助註解@EnableAutoConfiguration的功能。
  1. 在註解@EnableAutoConfiguration中又有兩個註解,@AutoConfigurationPackage,@EnableAutoConfiguration。
  1. 通過@AutoConfigurationPackage實現對於當前項目中Bean的進行載入;
  1. @EnableAutoConfiguration通過@Import({AutoConfigurationImportSelector.class})實現對於Pom引入的start中的XXAutoConfiguration的載入;
  1. @AutoConfigurationImportSelector類中通過SpringFactoriesLoader讀取 META-INF/spring.factories中key為org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的各個XXAutoConfiguration的值,然後springboot在結合各個start中的代碼完成對於XXAutoConfiguration中的Bean的載入動作;

到這裡是不是已經可以很瞭然對我們之前開發starter中的定義了啊,趕緊試試吧


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前言 redis在我們企業級開發中是很常見的,但是單個redis不能保證我們的穩定使用,所以我們要建立一個集群。 redis有兩種高可用的方案: High availability with Redis Sentinel(哨兵) Scaling with Redis Cluster(分片集群) ...
  • 有問必答 最近有好多讀者私信我,為什麼選擇GoFrame做電商項目的開發? 原因很簡單: 因為我司是用GoFrame做電商業務開發的,而且我司同事基本都是PHP轉Go的。GoFrame可以說是非常適合PHPer轉Gopher的開發框架。 在入職我司之前,我有使用Gin和go-micro框架,目前也正 ...
  • JavaSE:基礎語法 註釋 Java中的註釋有三種: 單行註釋:只能註釋當前行,以//開始,直到行結束 ​ //輸出HelloWorld! 多行註釋:註釋一段文字,以/ * 開始以 * / 結束! ​ /* 這是我們Java程式的主入口, main方法也是程式的主線程。 */ 文檔註釋:用於生產A ...
  • JZ78 把二叉樹列印成多行 題目 給定一個節點數為 n 二叉樹,要求從上到下按層列印二叉樹的 val 值,同一層結點從左至右輸出,每一層輸出一行, 將輸出的結果存放到一個二維數組中返回。 例如:給定的二叉樹是{1,2,3,#,#,4,5} [ [1], [2,3], [4,5] ] 方法 非遞歸層 ...
  • 1. 協議的作用 TCP/IP 中消息傳輸基於流的方式,沒有邊界 協議的目的就是劃定消息的邊界,制定通信雙方要共同遵守的通信規則 2. Redis 協議 如果我們要向 Redis 伺服器發送一條 set name Nyima 的指令,需要遵守如下協議 // 該指令一共有3部分,每條指令之後都要添加回 ...
  • JVM是運行在操作系統之上的,它與硬體沒有直接的交互。先說一下JVM的記憶體區域,當函數開始運行時,JVM拿到自己的記憶體將自己的記憶體區域進行了分割,分為五塊區域:線程共用的有堆、方法區,線程私有的有java棧、本地方法棧、程式計數器。 ...
  • 公司直招 急聘崗位 ♦telegram:@xiaobai04 @HRdajisi♦釘釘:馬新宇 零九四五五五壹零壹六吧♦Skype: live:.cid.d850fdc83f05e44a♦郵箱:[email protected] ♦技術部:薪資面議 薪資範圍25-100k 績效:MA ...
  • 來源:blog.csdn.net/randompeople/article/details/114917087 為什麼 java wait/notify 必須與 synchronized 一起使用 這個問題就是書本上沒怎麼講解,就是告訴我們這樣處理,但沒有解釋為什麼這麼處理?我也是基於這樣的困惑去了 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...