Spring Boot(更準(zhǔn)確地說(shuō)是 Spring 框架)對(duì) CGLIB 和 ASM 的重新打包(repackaging)是通過(guò)類重命名與隔離實(shí)現(xiàn)版本沖突避免的,核心思路是將這兩個(gè)庫(kù)的代碼 “嵌入” 到 Spring 自身的類路徑中,與外部引入的同名庫(kù)完全隔離。具體機(jī)制如下:
Spring 框架在構(gòu)建時(shí),會(huì)通過(guò)工具(如 jarjar 或自定義插件)將 CGLIB 和 ASM 的源碼(或字節(jié)碼)重命名并整合到 spring-core 模塊中,具體操作包括:
- 包名修改:將原生 CGLIB 的
net.sf.cglib.* 包路徑改為 org.springframework.cglib.*;將 ASM 的 org.objectweb.asm.* 改為 org.springframework.asm.*。
- 類名保持兼容:重命名后的類名(如
Enhancer、MethodInterceptor)與原生庫(kù)一致,但全限定名不同(因包名改變)。
例如:
- 原生 CGLIB 的代理類:
net.sf.cglib.proxy.Enhancer
- Spring 重打包后:
org.springframework.cglib.proxy.Enhancer
通過(guò)上述重命名,Spring 內(nèi)部使用的 CGLIB/ASM 與項(xiàng)目中可能引入的外部 CGLIB/ASM 成為完全獨(dú)立的兩套類,實(shí)現(xiàn)了以下隔離效果:
- 類加載隔離:JVM 會(huì)將不同包路徑的類視為完全不同的類,即使類名相同也不會(huì)沖突。例如,
net.sf.cglib.proxy.Enhancer 和 org.springframework.cglib.proxy.Enhancer 會(huì)被類加載器當(dāng)作兩個(gè)無(wú)關(guān)的類處理。
- 依賴隔離:Spring 內(nèi)部代碼(如 AOP 模塊)只會(huì)引用重打包后的類(
org.springframework.cglib.*),而項(xiàng)目中引入的外部庫(kù)(如第三方組件)若依賴原生 CGLIB/ASM,會(huì)使用 net.sf.cglib.* 或 org.objectweb.asm.*,兩者互不干擾。
- 防止 “版本打架”:CGLIB 和 ASM 是許多框架(如 Hibernate、MyBatis 等)的依賴,若 Spring 直接依賴原生庫(kù),可能與項(xiàng)目中其他庫(kù)引入的不同版本 CGLIB/ASM 沖突(例如方法簽名不一致、類結(jié)構(gòu)變化等)。
- 保證內(nèi)部兼容性:Spring 對(duì) CGLIB/ASM 的功能有特定依賴(如適配 Java 版本、修復(fù)特定 Bug),重打包后可確保內(nèi)部使用的版本完全符合自身需求,不受外部依賴影響。
- 簡(jiǎn)化用戶依賴管理:用戶無(wú)需手動(dòng)協(xié)調(diào) Spring 與其他庫(kù)的 CGLIB/ASM 版本,Spring 內(nèi)部的依賴被 “隱藏” 在
spring-core 中,對(duì)用戶透明。
假設(shè)項(xiàng)目中同時(shí)存在:
- Spring 內(nèi)置的重打包 CGLIB(
org.springframework.cglib.*)
- 外部引入的原生 CGLIB(
net.sf.cglib:3.3.0)
此時(shí):
- Spring AOP 會(huì)使用
org.springframework.cglib.proxy.Enhancer 創(chuàng)建代理;
- 第三方庫(kù)若使用 CGLIB,會(huì)引用
net.sf.cglib.proxy.Enhancer;
- 兩者在 JVM 中是完全獨(dú)立的類,不會(huì)因版本差異導(dǎo)致
NoSuchMethodError 或 ClassCastException 等沖突。
Spring 對(duì) CGLIB 和 ASM 的重新打包,本質(zhì)是通過(guò)包路徑重命名實(shí)現(xiàn)類隔離,使內(nèi)部依賴與外部依賴成為兩套獨(dú)立的代碼,從根本上避免了版本沖突。這種機(jī)制既保證了 Spring 自身功能的穩(wěn)定性,又不限制用戶引入其他版本的 CGLIB/ASM,是框架設(shè)計(jì)中解決依賴沖突的經(jīng)典方案。