MyBatis源碼分析の配置文件解析

文章目錄

  • 前言
  • 一、SqlSessionFactoryBuilder
    • 1.1、XMLConfigBuilder
    • 1.2、parse
  • 二、mappers標簽的解析
    • 2.1、cacheElement
      • 2.1.1、緩存策略
    • 2.2、buildStatementFromContext
      • 2.2.1、sql的解析


前言

??本篇主要介紹MyBatis源碼中的配置文件解析部分。MyBatis是對于傳統JDBC的封裝,屏蔽了傳統JDBC與數據庫進行交互,組裝參數,獲取查詢結果并自己封裝成對象的繁瑣過程。
??原生MyBatis首先需要配置mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><properties resource="jdbc.properties"/><environments default="dev"><environment id="dev"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="mapper/UserMapper.xml"/></mappers>
</configuration>

??并且指定數據源jdbc.properties

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

??創建數據庫訪問層接口:

public interface UserMapper {List<User> selectAll();User selectById(int id);void insert(User user);void update(User user);void delete(int id);
}

??以及對應的xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.mybatis.mapper.UserMapper"><cache/><resultMap id="userResultMap" type="com.example.mybatis.entity.User"><id property="id" column="id"/><result property="name" column="name"/><result property="age" column="age"/></resultMap><select id="selectAll" resultMap="userResultMap">SELECT * FROM users</select><select id="selectById" resultMap="userResultMap" parameterType="int">SELECT * FROM users WHERE id = #{id}</select><insert id="insert" parameterType="com.example.mybatis.entity.User">INSERT INTO users (name, age) VALUES (#{name}, #{age})</insert><update id="update" parameterType="com.example.mybatis.entity.User">UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}</update><delete id="delete" parameterType="int">DELETE FROM users WHERE id = #{id}</delete>
</mapper>

??mybatis-config.xml常見的標簽:

標簽作用
<settings>控制 MyBatis 全局行為(緩存、懶加載、日志等)
<typeAliases>設置類型別名,簡化 Mapper XML 中類名書寫
<typeHandlers>自定義類型轉換器(Java類型 ? JDBC類型)
<plugins>注冊插件(如分頁插件、SQL打印等)
<objectFactory>自定義對象創建邏輯
<environments>配置數據庫環境及事務管理
<mappers>注冊 Mapper 映射文件或 Mapper 接口

??原生MyBatis的使用,其中讀取配置文件并進行解析,主要體現在SqlSessionFactoryBuilderbuild方法中:

public class Main {public static void main(String[] args) throws Exception {//將xml構筑成configuration配置類Reader reader = Resources.getResourceAsReader("mybatis-config.xml");//解析xml,注冊成SqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);try (SqlSession session = sqlSessionFactory.openSession()) {User user = session.selectOne("com.example.mybatis.mapper.UserMapper.selectById", 1);System.out.println(user);}}
}

一、SqlSessionFactoryBuilder

1.1、XMLConfigBuilder

??在調用SqlSessionFactoryBuilderbuild方法時,首先會去創建一個XMLConfigBuilder,目的是構建一個XML配置文件解析器對象。
在這里插入圖片描述??其中的核心代碼,這段代碼的作用是注冊別名,將配置文件中的 “JDBC”、"POOLED"等關鍵詞和實際的類型進行綁定。
在這里插入圖片描述

別名實際類用途
"JDBC"JdbcTransactionFactoryJDBC事務管理器(默認事務方式)
"MANAGED"ManagedTransactionFactory受容器管理的事務(如 Spring)
"JNDI"JndiDataSourceFactory從 JNDI 獲取數據源
"POOLED"PooledDataSourceFactory數據庫連接池(MyBatis 內置)
"UNPOOLED"UnpooledDataSourceFactory不使用連接池的數據源
"PERPETUAL"PerpetualCache永久緩存
"FIFO"FifoCache先進先出緩存
"LRU"LruCache最近最少使用緩存
"SOFT"SoftCache基于 SoftReference 的緩存
"WEAK"WeakCache基于 WeakReference 的緩存
"DB_VENDOR"VendorDatabaseIdProvider根據數據庫類型自動切換 SQL
"XML"XMLLanguageDriverMyBatis 默認的 XML SQL 語言驅動器
"RAW"RawLanguageDriver原生 SQL 寫法語言驅動器
"SLF4J"Slf4jImpl使用 SLF4J 的日志輸出
"COMMONS_LOGGING"JakartaCommonsLoggingImpl使用 Commons Logging 日志
"LOG4J"Log4jImpl使用 Log4j 日志
"LOG4J2"Log4j2Impl使用 Log4j2 日志
"JDK_LOGGING"Jdk14LoggingImpl使用 JDK 內建日志
"STDOUT_LOGGING"StdOutImpl輸出日志到控制臺
"NO_LOGGING"NoLoggingImpl不輸出日志
"CGLIB"CglibProxyFactory使用 CGLIB 動態代理
"JAVASSIST"JavassistProxyFactory使用 Javassist 動態代理

1.2、parse

??真正解析配置文件的是利用上一步構造出的XMLConfigBuilderparse方法,首先會進行判斷,如果已經解析過,則拋出異常,不會重復解析:
在這里插入圖片描述??否則就將標記設置為true。并且執行parseConfiguration方法,從根節點進行解析:
??每一行都對應了一個 <mybatis-config.xml> 中的標簽,逐步填充 Configuration 對象內容:
在這里插入圖片描述

/*** 解析 <configuration> 根節點的各個子標簽,并將配置信息填充到 Configuration 對象中*/
private void parseConfiguration(XNode root) {try {// 【1】先解析 <properties> 標簽(必須最優先解析),以便后續標簽中的占位符 ${} 能被正確替換propertiesElement(root.evalNode("properties"));// 【2】解析 <settings> 標簽,將其內容轉換為 Properties 對象Properties settings = settingsAsProperties(root.evalNode("settings"));// 【3】解析 settings 中的 vfsImpl 屬性(如果配置了自定義 VFS 實現類)loadCustomVfs(settings);// 【4】解析 settings 中的 logImpl 屬性(設置日志實現類,如 LOG4J、STDOUT_LOGGING 等)loadCustomLogImpl(settings);// 【5】解析 <typeAliases> 標簽,注冊用戶自定義的別名或包掃描別名typeAliasesElement(root.evalNode("typeAliases"));// 【6】解析 <plugins> 標簽,注冊 MyBatis 插件(如分頁插件、SQL 攔截器等)pluginElement(root.evalNode("plugins"));// 【7】解析 <objectFactory> 標簽,設置自定義對象工廠(用于實例化結果對象)objectFactoryElement(root.evalNode("objectFactory"));// 【8】解析 <objectWrapperFactory> 標簽,自定義對象包裝器(封裝結果對象屬性訪問行為)objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));// 【9】解析 <reflectorFactory> 標簽,自定義反射器工廠(高級反射行為控制)reflectorFactoryElement(root.evalNode("reflectorFactory"));// 【10】將 <settings> 中的配置項應用到 Configuration 對象中settingsElement(settings);// 【11】解析 <environments> 標簽,注冊事務管理器和數據源配置(必須在 objectFactory 之后執行)environmentsElement(root.evalNode("environments"));// 【12】解析 <databaseIdProvider> 標簽,支持數據庫廠商識別(如區分 MySQL、Oracle)databaseIdProviderElement(root.evalNode("databaseIdProvider"));// 【13】解析 <typeHandlers> 標簽,注冊自定義類型處理器(TypeHandler)typeHandlerElement(root.evalNode("typeHandlers"));// 【14】解析 <mappers> 標簽,加載 Mapper 映射器(包括 XML 和接口方式)mapperElement(root.evalNode("mappers"));} catch (Exception e) {// 如果解析過程中發生異常,則封裝為 BuilderException 拋出throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);}
}

??當解析完成后,會得到一個configuration對象,其中就包含了配置文件中的各種值。相當于此時的xml配置文件已經轉化為了configuration對象。最后還會將其再次包裝成SqlSessionFactory,后續會利用SqlSessionFactory進行sql相關邏輯的執行。
在這里插入圖片描述??其中最關鍵的是mappers標簽的解析。

二、mappers標簽的解析

??mapperElement方法,首先會拿到mappers根標簽,然后進行解析。

/*** 解析 <mappers> 標簽,支持三種加載方式:package、resource/url、class*/
private void mapperElement(XNode parent) throws Exception {if (parent != null) {// 遍歷 <mappers> 下的所有子節點(可能是 <package> 或 <mapper>)for (XNode child : parent.getChildren()) {// 情況1:<package name="com.xxx.mapper"/>,批量注冊包下所有 Mapper 接口if ("package".equals(child.getName())) {String mapperPackage = child.getStringAttribute("name");// 自動掃描指定包下的所有接口,并注冊到 Configuration 中configuration.addMappers(mapperPackage);} else {// 情況2~4:單個 <mapper> 節點,通過 resource/url/class 指定加載方式String resource = child.getStringAttribute("resource"); // 從 classpath 中加載 Mapper XMLString url = child.getStringAttribute("url");           // 從網絡路徑加載 Mapper XMLString mapperClass = child.getStringAttribute("class"); // 直接加載 Mapper 接口類// 情況2:只指定 resource,加載 Mapper XML 文件if (resource != null && url == null && mapperClass == null) {ErrorContext.instance().resource(resource); // 設置錯誤上下文信息try (InputStream inputStream = Resources.getResourceAsStream(resource)) {XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());mapperParser.parse(); // 解析 Mapper XML,注冊語句映射}// 情況3:只指定 url,加載遠程 Mapper XML 文件} else if (resource == null && url != null && mapperClass == null) {ErrorContext.instance().resource(url);try (InputStream inputStream = Resources.getUrlAsStream(url)) {XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());mapperParser.parse(); // 同樣調用解析邏輯}// 情況4:只指定 class,注冊 Mapper 接口類(無 XML 時適用)} else if (resource == null && url == null && mapperClass != null) {Class<?> mapperInterface = Resources.classForName(mapperClass);configuration.addMapper(mapperInterface); // 注冊接口類到 MapperRegistry// 情況5:配置沖突,三種方式只能選一種,否則拋異常} else {throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");}}}}
}

??案例中對應的是情況2,首先會注冊一個mapper解析器,然后調用其parse方法對案例中UserMapper.xml進行解析,在該方法中,首先會進行判斷,如果已經進行過解析,則不會重復解析。
在這里插入圖片描述??解析的核心方法在于configurationElement,同樣是對于xml中的各種標簽再次分類解析:
在這里插入圖片描述??這里重點看一下cacheElement以及buildStatementFromContext

2.1、cacheElement

??cacheElement和Mybatis的二級緩存有關。簡單的說,Mybatis有兩級緩存:

  • 一級緩存是SqlSession 級別的,并且默認開啟。
  • 二級緩存是Mapper 映射級別,默認不開啟,如果需要,應該在某個mapper.xml中使用cache標簽開啟。

??cacheElement方法正是解析mapper.xml中的cache標簽:

/*** 解析 <cache> 標簽,構建二級緩存對象并注冊到 Configuration 中。*/
private void cacheElement(XNode context) {// 1. 判斷 <cache> 標簽是否存在if (context != null) {// 2. 解析緩存類型(默認是 PERPETUAL,即 PerpetualCache)String type = context.getStringAttribute("type", "PERPETUAL");Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);// 3. 解析緩存淘汰策略(默認是 LRU,即最近最少使用)String eviction = context.getStringAttribute("eviction", "LRU");Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);// 4. 緩存刷新間隔(可選):指定自動清空緩存的時間(毫秒)Long flushInterval = context.getLongAttribute("flushInterval");// 5. 緩存大小(可選):最大緩存對象個數Integer size = context.getIntAttribute("size");// 6. 是否為讀寫緩存(readOnly=false 表示使用序列化;true 表示共享引用)//    readWrite = true 表示開啟對象副本,確保線程安全boolean readWrite = !context.getBooleanAttribute("readOnly", false);// 7. 是否阻塞:當緩存正在被其他線程刷新時,是否阻塞等待boolean blocking = context.getBooleanAttribute("blocking", false);// 8. 獲取 <cache> 中配置的其他 <property> 子節點Properties props = context.getChildrenAsProperties();// 9. 構建緩存并注冊到 Configuration,封裝為 MapperBuilderAssistant.useNewCache()builderAssistant.useNewCache(typeClass,          // 緩存類型類(如 PerpetualCache)evictionClass,      // 淘汰策略類(如 LruCache)flushInterval,      // 緩存刷新間隔size,               // 緩存容量readWrite,          // 是否使用讀寫模式blocking,           // 是否阻塞模式props               // 自定義屬性);}
}

??在useNewCache中,最終會調用CacheBuilderbuild方法:
在這里插入圖片描述 ??build方法中運用到了裝飾器模式,所有的Cache都實現了一個共同的父類Cache。
??在**cache = newCacheDecoratorInstance(decorator, cache);這一行代碼中,傳入LruCache和當前的Cache實例(PERPETUAL),將PERPETUAL包裝到LRU中:(LruCache的delegate屬性,指向的是傳入的PerpetualCache實例)
在這里插入圖片描述
在這里插入圖片描述??然后繼續執行到
cache = setStandardDecorators(cache);**這一行代碼,會繼續進行裝飾器的包裝:
在這里插入圖片描述??setStandardDecorators方法,對于Cache實例層層包裝,賦值給各自的delegate屬性:
在這里插入圖片描述??包裝完成的層次:SynchronizedCache線程同步緩存區->LoggingCache統計命中率以及打印日志->SerializedCache序列化->LruCache最少使用->PerpetualCache默認。
在這里插入圖片描述

2.1.1、緩存策略

??默認的PerpetualCache,使用的是HashMap進行存儲。
在這里插入圖片描述
??而LruCache,為了實現最近最少使用的機制,使用了LinkedHashMap的數據結構,并且重寫了它的removeEldestEntry方法,關鍵在于,LinkedHashMap構造時第三個參數為 true 表示按訪問順序排列:
在這里插入圖片描述

LruCache cache = new LruCache(new PerpetualCache("myCache"));
cache.setSize(3);cache.put("A", 1);  // A
cache.put("B", 2);  // A B
cache.put("C", 3);  // A B C
cache.get("A");     // B C A (A 被訪問過,移到尾部)
cache.put("D", 4);  // C A D(B 被淘汰)

??SynchronizedCache,每個方法上通過加synchronized保證線程安全:
在這里插入圖片描述 ??LoggingCache,會記錄日志,以及統計緩存命中次數:
在這里插入圖片描述

2.2、buildStatementFromContext

??buildStatementFromContext是用來解析 select、insert、update、delete 標簽中sql語句的方法,首先會解析出這些節點,然后進行循環,獲取到XMLStatementBuilder后,執行parseStatementNode方法:
在這里插入圖片描述??在parseStatementNode方法中有幾個關鍵點,這一段代碼會判斷當前的標簽是否為select,如果是select標簽,則不會清除一級緩存(增刪改會清除),以及判斷是否使用二級緩存(默認 select 使用)
在這里插入圖片描述

2.2.1、sql的解析

??真正執行解析sql的是下圖中的代碼:
在這里插入圖片描述??同樣地會先去構建一個XMLScriptBuilder,然后調用其parseScriptNode方法進行解析:
在這里插入圖片描述??在parseScriptNode方法中,首先會解析 SQL 標簽中的所有子標簽,然后去進行判斷:

  • 包含動態 SQL(即是否包含 if、choose、${} 等動態節點)構建 DynamicSqlSource(運行時動態拼接 SQL)
  • 不包含動態 SQL(即是否包含 if、choose、${} 等動態節點)構建 RawSqlSource(直接編譯成靜態 SQL,提升效率)

在這里插入圖片描述??MixedSqlNode對象,實現了SqlNode接口,SqlNode是所有動態 SQL節點的統一接口,而MixedSqlNode代表了 一整個 SQL 腳本塊,比如select標簽中所有內容就會變成一個 MixedSqlNode。

SqlNode 接口

├── MixedSqlNode // 組合節點
├── StaticTextSqlNode // 靜態文本節點:普通 SQL 字符串
├── TextSqlNode // 動態文本節點:包含 ${}
├── IfSqlNode // if 標簽
├── ChooseSqlNode // choose/when/otherwise
├── ForEachSqlNode // foreach
├── WhereSqlNode // where
├── TrimSqlNode // trim
├── SetSqlNode // set
└── BindSqlNode // bind

??用一個案例說明,假如我在mapper.xml中定義了如下的sql語句:

<select id="findUser" parameterType="map" resultType="User">SELECT * FROM user<where><if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where>
</select>

??則生成的結構如下:

MixedSqlNode
├── StaticTextSqlNode(“SELECT * FROM user”)
└── WhereSqlNode
└── MixedSqlNode
├── IfSqlNode(test=“name != null”) → TextSqlNode(“AND name = #{name}”)
└── IfSqlNode(test=“age != null”) → TextSqlNode(“AND age = #{age}”)


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

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

相關文章

golang快速上手基礎語法

變量 第一種&#xff0c;指定變量類型&#xff0c;聲明后若不賦值&#xff0c;使用默認值0 package mainimport "fmt"func main() {var a int //第一種&#xff0c;指定變量類型&#xff0c;聲明后若不賦值&#xff0c;使用默認值0。fmt.Printf(" a %d\n"…

Java中的訪問修飾符有哪些

在 Java 中&#xff0c;訪問修飾符&#xff08;Access Modifiers&#xff09;用于控制類、方法、變量和構造器的訪問權限。Java 提供了四種訪問修飾符&#xff0c;分別是&#xff1a; publicprotecteddefault&#xff08;包私有&#xff0c;沒有顯式修飾符&#xff09;private…

【公務員考試】高效備考指南

高效備考指南&#xff1a;從計劃制定到心態調整的全面攻略 公務員考試競爭激烈&#xff0c;備考過程既需要科學規劃&#xff0c;也需要持之以恒的努力。結合多位高分考生的經驗與專業機構的指導&#xff0c;本文整理了一套系統化的備考策略&#xff0c;涵蓋目標設定、學習方法…

工程實踐:如何使用SU17無人機來實現室內巡檢任務

阿木實驗室最近發布了科研開發者版本的無人機SU17&#xff0c;該無人機上集成了四目視覺&#xff0c;三維激光雷達&#xff0c;云臺吊艙&#xff0c;高算力的機載計算機&#xff0c;是一個非常合適的平臺用于室內外巡檢場景。同時阿木實驗室維護了多個和無人機相關的開源項目。…

強大的CSS變量

在 CSS 中&#xff0c;變量&#xff08;Custom Properties&#xff09; 允許你定義可重用的值&#xff0c;方便在整個樣式表中使用和修改。CSS 變量的基本語法如下&#xff1a; 1. 定義 CSS 變量 CSS 變量通常在 :root 偽類中定義&#xff0c;以便它們可用于整個文檔&#xf…

藍橋杯嵌入式賽道復習筆記1(led點亮)

前言 基礎的文件創建&#xff0c;參賽資源代碼的導入&#xff0c;我就不說了&#xff0c;直接說CubeMX的配置以及代碼邏輯思路的書寫&#xff0c;在此我也預祝大家人人拿國獎 理論講解 原理圖簡介 1.由于存在PC8引腳到PC15引腳存在沖突&#xff0c;那么官方硬件給的解決方案…

Linux進程1.0--task_struct

1.硬件&#xff1a;馮諾依曼體系結構&#xff1a; 單個分析&#xff1a;、 數據流向&#xff1a;數據必須先進入輸入設備&#xff0c;再到存儲器&#xff0c;然后由存儲器給控制器&#xff0c;控制器收到以后進行相應的處理后&#xff0c;再傳回存儲器&#xff0c;存儲器最終傳…

本地部署Jina AI Reader:用Docker打造你的智能解析引擎

本地部署Jina AI Reader&#xff1a;用Docker打造你的智能解析引擎 &#x1f31f; 引言&#xff1a;為什么需要本地部署&#xff1f;&#x1f4cc; 場景應用圖譜&#x1f527; 部署指南&#xff08;Linux環境&#xff09;1. 環境準備2. Docker部署3. 驗證服務狀態 &#x1f680…

貪心算法簡介(greed)

前言&#xff1a; 貪心算法&#xff08;Greedy Algorithm&#xff09;是一種在每個決策階段都選擇當前最優解的算法策略&#xff0c;通過局部最優的累積來尋求全局最優解。其本質是"短視"策略&#xff0c;不回溯已做選擇。 什么是貪心、如何來理解貪心(個人對貪心的…

代碼隨想錄day17 二叉樹part05

654.最大二叉樹 給定一個不重復的整數數組 nums 。 最大二叉樹 可以用下面的算法從 nums 遞歸地構建: 創建一個根節點&#xff0c;其值為 nums 中的最大值。 遞歸地在最大值 左邊 的 子數組前綴上 構建左子樹。 遞歸地在最大值 右邊 的 子數組后綴上 構建右子樹。 返回 nums …

宇樹人形機器人開源模型

1. 下載源碼 https://github.com/unitreerobotics/unitree_ros.git2. 啟動Gazebo roslaunch h1_description gazebo.launch3. 仿真效果 H1 GO2 B2 Laikago Z1 4. VMware: vmw_ioctl_command error Invalid argument 這個錯誤通常出現在虛擬機環境中運行需要OpenGL支持的應用…

通過特征值和特征向量實現的圖像壓縮和特征提取

前文&#xff0c;我們在學習人工智能的線性代數基礎的時候&#xff0c;就了解到&#xff0c;矩陣在人工智能中被廣泛使用&#xff0c;接下來我們就從大家非常常見的圖像開始&#xff0c;深度理解矩陣在人工智能中的應用。有關線性代數基礎的文章可以看的我CSDN:人工智能中的線性…

藍橋杯2023年第十四屆省賽真題-整數刪除 暴力-->鏈表+小根堆

題目來自DOTCPP&#xff1a; 思路&#xff1a; ①每次找到數列中的最小值下標&#xff0c;然后用狀態數組st標記它&#xff0c;相當與刪除它&#xff0c;之后就不會訪問它。 ②對最小值下標左邊和右邊判斷一下&#xff0c;看有沒有數字&#xff0c;如果有就把最小值加到兩邊第…

springboot438-基于SpringBoot的數字化教學資源管理系統(源碼+數據庫+純前后端分離+部署講解等)

&#x1f495;&#x1f495;作者&#xff1a; 愛笑學姐 &#x1f495;&#x1f495;個人簡介&#xff1a;十年Java&#xff0c;Python美女程序員一枚&#xff0c;精通計算機專業前后端各類框架。 &#x1f495;&#x1f495;各類成品Java畢設 。javaweb&#xff0c;ssm&#xf…

藍橋杯刷題——第十五屆藍橋杯大賽軟件賽省賽C/C++ 大學 B 組

一、0握手問題 - 藍橋云課 算法代碼&#xff1a; #include <iostream> using namespace std; int main() {int sum0;for(int i49;i>7;i--)sumi;cout<<sum<<endl;return 0; } 直接暴力&#xff0c;題意很清晰&#xff0c;累加即可。 二、0小球反彈 - 藍…

跨境衛士跟vps哪個更好用?跨境衛士為賣家提供固定IP環境

跨境衛士是通過為賣家提供固定的環境 i p來隔離本地電腦環境&#xff0c;為賣家創造一個真實獨立的物理環境&#xff0c;讓買家再任意電腦&#xff0c;任意網絡下都能夠安全的管理賬號。跨境衛士和紫鳥原理一樣&#xff0c;是通過為賣家提供固定的環境 i p來隔離本地電腦環境&a…

coding ability 展開第四幕(滑動指針——鞏固篇)超詳細!!!!

文章目錄 前言水果成籃思路 找到字符串中所有字母異位詞思路 串聯所有單詞的子串思路 最小覆蓋子串思路 總結 前言 本專欄上一篇博客&#xff0c;帶著大家從認識滑動窗口到慢慢熟悉 相信大家對滑動窗口已經有了大概的認識 其實主要就是抓住——一段連續的區間 今天來學習一些滑…

圖解AUTOSAR_CP_BSW_General

AUTOSAR BSW通用規范詳解 AUTOSAR基礎軟件模塊通用規范與架構解析 目錄 1. 概述 1.1. AUTOSAR BSW通用規范簡介1.2. 文檔目的與范圍2. BSW模塊文件結構 2.1. 標準文件組織2.2. 命名規范3. BSW模塊接口 3.1. 接口類型3.2. 模塊API3.3. 配置參數4. BSW通用架構 4.1. 分層架構4.2.…

如何在Futter開發中做性能優化?

目錄 1. 避免不必要的Widget重建 問題&#xff1a;頻繁調用setState()導致整個Widget樹重建。 優化策略&#xff1a; 2. 高效處理長列表 問題&#xff1a;ListView一次性加載所有子項導致內存暴漲。 優化策略&#xff1a; 3. 圖片加載優化 問題&#xff1a;加載高分辨率…

組件通信框架ARouter原理剖析

組件通信框架ARouter原理剖析 一、前言 隨著Android應用規模的不斷擴大&#xff0c;模塊化和組件化開發變得越來越重要。ARouter作為一個用于幫助Android應用進行組件化改造的框架&#xff0c;提供了一套完整的路由解決方案。本文將深入分析ARouter的核心原理和實現機制。 二…