当前位置: 首页 > 后端技术 > Java

JavaSPI机制,“可插拔”的奥秘~

时间:2023-04-01 16:08:29 Java

澶у濂斤紝鎴戞槸灏忚彍銆備竴涓笇鏈涙垚涓哄惞鐗沊鐨勭敺浜猴紝璋堝缓绛戯紒濡傛灉浣犱篃鎯虫垚涓烘垜鎯虫垚涓虹殑浜猴紝鎴栬€呰窡鐫€鎴戝仛浼达紝璁╁皬鑿滀笉鍐嶅鍗曪紒鏈枃涓昏浠嬬粛SPI鏈哄埗銆傚鏋滈渶瑕侊紝鍙互鍙傝€冦€傚鏋滄湁甯姪锛屽埆蹇樹簡鐐硅禐鉂ュ井淇″叕浼楀彿宸插紑閫氥€傚湪涓婁竴绡囨枃绔犱腑锛屾垜浠皥鍒颁簡Agent鍦↗ava涓殑鐢ㄦ硶銆傚緢澶氭湅鍙嬭寰楄繖绉嶆柟寮忔瘮杈冨亸锛屽湪骞虫椂鐨勫紑鍙戜腑骞朵笉甯哥敤锛堝嚑涔庢病鐢級銆傚叾瀹炲苟涓嶅父鐢紝鍥犱负鏄寕鍦ㄩ」鐩笂鐨勩€傞」鐩笉甯镐娇鐢ㄥ苟涓嶄唬琛ㄦ柟娉曟満鍒朵笉甯哥敤銆傛墍浠ワ紝寰堝鏃跺€欐垜浠笉鑳藉湪瀛︿範涓潗瑙嗕笉绠°€傚鏋滄垜浠涓哄畠涓嶄細鍦ㄩ」鐩腑浣跨敤锛屾垜浠氨鍙互涓嶅瀹冦€傛垜浠線寰€鏃犳硶闅忕潃椤圭洰鐨勬垚闀胯€屾垚闀縹锛佷笂涓€璺宠浆鍏ュ彛锛欽ava楂樼骇鐢ㄦ硶锛屽啓涓猵roxy鏉ヤ镜鐣ヤ綘锛熼偅涔堣繖绡囨枃绔犳垜浠氨缁х画璇磋Java涓殑鍙︿竴涓煡璇嗙偣锛岄偅灏辨槸SPI鏈哄埗锛屼箥涓€鐪嬭繕鏄瘮杈冮檶鐢熺殑锛岃繖涓椂鍊欎笉瑕侀€€缂╋紒寰€涓嬬湅锛屼綘浼氬彂鐜板湪姝e父鐨勫紑鍙戜腑缁忓父鐪嬪埌锛?.SPI鎴戜滑鐨勬枃绔犱互闂涓哄鍚戯紝浠ラ棶棰橀┍鍔ㄥ涔犮€傚皬鑿滃厛鎶涘嚭浜嗗嚑涓棶棰樸€備笅闈㈠皢瀵硅繖浜涢棶棰樿繘琛岃В閲婂拰灞曞紑銆備粈涔堟槸SPI锛烻PI鍜孉PI涔嬮棿鐨勫尯鍒紵浣犲湪鏃ュ父鐢熸椿涓娇鐢⊿PI鍚楋紵1.浠€涔堟槸SPISPI锛熸槸涓変釜璇峉鈥嬧€媏rviceProviderInterface鐨勭缉鍐欙紝瀛楅潰鎰忔€濇槸锛氭湇鍔℃彁渚涜€呮帴鍙c€傚畠鏄疛ava鎻愪緵鐨勪竴缁勭敱绗笁鏂瑰疄鐜版垨鎵╁睍鐨勬帴鍙o紝鍙敤浜庡惎鐢ㄦ鏋舵墿灞曞拰鏇挎崲缁勪欢銆傚叿浣撲綔鐢ㄥ氨鏄负杩欎簺鎵╁睍API瀵绘壘鏈嶅姟瀹炵幇銆侸avaSPI鏄疛DK鍐呯疆鐨勬湇鍔″彂鐜版満鍒躲€傚畠閫氬父鐢ㄤ簬鍒涘缓鍏锋湁鍙墿灞曞拰鍙浛鎹㈢粍浠剁殑搴旂敤绋嬪簭銆傚畠鏄疛ava妯″潡鍖栧拰鎻掍欢鍖栫殑鍏抽敭銆傝繖閲屾垜浠彁鍒颁簡涓や釜姒傚康锛屽嵆妯″潡鍖栧拰鎻掍欢鍖栥€傛ā鍧楀寲寰堝ソ鐞嗚В锛屽氨鏄妸涓€涓」鐩垎鎴愬涓ā鍧楋紝妯″潡涔嬮棿鍙兘瀛樺湪鐩镐簰渚濊禆锛堜篃灏辨槸閫氳繃maven锛夈€備娇鐢ㄥ井鏈嶅姟寮€鍙戠殑鍚屽骞朵笉闄岀敓銆傚鏋滀綘涓嶄娇鐢ㄥ井鏈嶅姟寮€鍙戯紝涔熸病鏈夊叧绯伙紝涓轰簡鍦ㄥ崟涓」鐩腑瀹氫箟鎺у埗銆佹湇鍔″拰瀛樺偍灞傦紝姣忎釜瀛楁涔熶細琚崟鐙彁鍙栧埌妯″潡涓紝鑰屼笉鏄互涓€涓洰褰晘2.绫诲姞杞芥満鍒朵笂闈㈡垜浠凡缁忔彁鍒颁簡SPI杩欎釜姣旇緝娴呯殑姒傚康銆傝繖閲岀殑灏忚彍涓嶆墦绠楃洿鎺ユ繁鍏PI銆傚湪娣卞叆SPI涔嬪墠锛屾垜浠厛浜嗚В涓€涓婮ava涓殑绫诲姞杞芥満鍒躲€傜被鍔犺浇鏈哄埗鍦ㄥ疄闄呭紑鍙戜腑鍙兘娌℃湁鑰冭檻鍒帮紝浣嗗畠鏃犲涓嶅湪锛岃繖涔熸槸闈㈣瘯涓殑鐑棬璇濋銆傚湪JVM涓紝绫诲姞杞藉櫒榛樿閲囩敤鍙屼翰濮旀淳鐨勫師鍒欍€傞粯璁ょ殑绫诲姞杞藉櫒鍖呮嫭BootstarpClassLoader銆丒xtensionClassLoader鍜孲ystemClassLoader锛堝簲鐢ㄧ被鍔犺浇鍣級銆傚綋鐒朵篃鍙互鏈夎嚜瀹氫箟鐨勭被鍔犺浇鍣▇鑷畾涔夌殑绫诲姞杞藉櫒鍙互閫氳繃缁ф壙java.lang.classloader鏉ュ疄鐜板悇涓被鍔犺浇鍣ㄧ殑浣滅敤鍩熷涓嬶細BootstrapClassLoader锛氳礋璐e姞杞絩t.jar鍖呬腑鐨刢lass鏂囦欢JDK鑷甫锛屾槸鎵€鏈夌被鍔犺浇鐨勭埗绫籈xtensionClassLoader锛氳礋璐e姞杞絡ava鎵╁睍绫诲簱浠巎re/lib/ect鎴杍ava.ext.dirs绯荤粺灞炴€ф寚瀹氱殑鐩綍鍔犺浇绫籗ystemClassLoader锛氳礋璐d粠绫昏矾寰勭幆澧冨彉閲忓姞杞界被鏂囦欢绫诲姞杞界户鎵垮叧绯诲浘濡備笅锛?锛夊弻浜插鎵樻ā鍨嬩粈涔堟槸鍙屼翰濮旀墭妯″瀷锛熷綋涓€涓被鍔犺浇鍣ㄦ帴鏀跺埌鍔犺浇涓€涓被鐨勪换鍔℃椂锛屽畠浼氬厛浜ょ粰瀹冪殑鐖跺姞杞藉櫒鏉ュ畬鎴愶紝涓€绾т竴绾э紝鎵€浠ユ渶鍚庝細浼犻€掔粰BootstrapClassLoader鍔犺浇锛屽彧鏈夊綋鐖跺姞杞藉櫒鏃犳硶瀹屾垚鍔犺浇涓轰粈涔堣杩欐牱璁捐锛岀劧鍚庡啀灏濊瘯鑷繁鍔犺浇鍛紵1.鍙屼翰濮旀墭鍘熷垯鍙互閬垮厤鍚屼竴涓被鐨勯噸澶嶅姞杞姐€傛瘡涓姞杞藉櫒鍦ㄦ墽琛岀被鍔犺浇浠诲姟鏃堕兘浼氬鎵樺叾鐖剁被鍔犺浇鍣ㄨ繘琛屽姞杞姐€傚鏋滅埗绫诲姞杞戒笉鍑烘潵锛屽氨鑷繁鍔犺浇锛岄伩鍏嶉噸澶嶅姞杞姐€傛儏鍐典簩銆佺被鍔犺浇鐨勫畨鍏ㄦ€у彲浠ュ緱鍒颁繚璇併€傛棤璁哄摢涓姞杞藉櫒鍔犺浇杩欎釜绫伙紝鏈€缁堥兘浼氬鎵樼粰椤跺眰鍔犺浇鍣ㄥ姞杞姐€備繚璇佷换浣曞姞杞藉櫒鏈€缁堥兘浼氬緱鍒扮浉鍚岀殑绫诲璞°€傚姞杞借繃绋嬪涓嬶細杩欐牱鍋氱殑缂虹偣鏄粈涔堬紵瀛愮被鍔犺浇鍣ㄥ彲浠ヤ娇鐢ㄧ埗绫诲姞杞藉櫒宸茬粡鍔犺浇鐨勭被锛屼絾鏄埗绫诲姞杞藉櫒涓嶈兘浣跨敤瀛愮被鍔犺浇鍣ㄥ姞杞界殑绫伙紙绫讳技浜庣户鎵垮叧绯伙級銆傝繖閲屽彲浠ヨ皥璋圝avaSPI銆侸ava鎻愪緵浜嗗緢澶氭湇鍔℃彁渚涜€呮帴鍙o紙SPI锛夛紝鍏佽绗笁鏂规彁渚涜繖浜涙帴鍙g殑瀹炵幇锛屾瘮濡傛暟鎹簱涓殑SPI鏈嶅姟鈥斺€擩DBC銆傝繖浜汼PI鎺ュ彛鐢盝ava鏍稿績绫绘彁渚涳紝瀹炴柦鑰呯‘瀹炴槸绗笁鏂癸紝鎵€浠ヤ細鏈夐棶棰樸€侾rovider鐢盉ootstrapClassLoader鍔犺浇锛宨mplementer鐢辩涓夋柟鑷畾涔夌被鍔犺浇鍣ㄥ姞杞姐€傝繖鏃跺€欓《灞傜被鍔犺浇鏄棤娉曡瀛愮被鍔犺浇鍣ㄥ姞杞界殑銆傜被瑙e鏋滆瑙e喅杩欎釜闂锛屽氨寰楁墦鐮村弻浜插娲剧殑鍘熷垯銆傚彲浠ヤ娇鐢ㄧ嚎绋嬩笂涓嬫枃绫诲姞杞藉櫒锛圕ontextClassLoader锛夋潵鍔犺浇Java銆傞粯璁ょ殑搴旂敤绋嬪簭涓婁笅鏂囧姞杞藉櫒浣跨敤AppClassLoader銆傚鏋滆浣跨敤鐖剁被鍔犺浇鍣ㄤ粠瀛愮被鍔犺浇鍣ㄥ姞杞界被鍙互浣跨敤Thread.currentThread().getContextClassLoader()渚嬪锛屽鏋滄垜浠鍔犺浇璧勬簮锛屽彲浠ヤ娇鐢ㄥ涓嬫柟娉曪細//浣跨敤绾跨▼涓婁笅鏂囩被鍔犺浇鍣ㄥ姞杞借祫婧恜ublicstaticvoidmain(String[]args)throwsException{Stringname="java/sql/Array.class";鏋氫妇urls=Thread.currentThread().getContextClassLoader().getResources(name);while(urls.hasMoreElements()){URLurl=urls.nextElement();绯荤粺銆俹ut.println(url.toString());}}3.JavaSPI璇村畬绫诲姞杞芥満鍒讹紝鎴戜滑鍐嶅洖鍒癑avaSPI銆傝鎴戜滑閫氳繃渚嬪瓙鐔熸倝涓€涓婼PI鐨勪娇鐢ㄣ€備娇鐢ㄨ繃绋嬪浘濡備笅锛氭洿閫氫織鐨勭悊瑙o紝SPI鍏跺疄鏄竴绉嶇瓥鐣ユā寮忕殑瀹炵幇锛屽熀浜庢帴鍙g紪绋嬪拰璇诲彇閰嶇疆鏂囦欢銆傝繖涔熺鍚堟垜浠殑缂栫▼鏂瑰紡锛氬彲鎻掓嫈~浣跨敤绀轰緥濡備笅锛氶」鐩粨鏋勶細ICustomSvc:ServiceProviderInterface(鍗砈PI)CustomSvcOne/CustomSvcTwo:Implementer(杩欓噷鍙互鐩存帴鍦ㄩ」鐩腑瀹炵幇锛屾垨鑰呴€氳繃jar鍖呭鍏ユ柟娉曪級cbuc.life.spi.service.ICustomSvc:閰嶇疆鏂囦欢鍐呭锛氱劧鍚庢垜浠惎鍔–ustomTest鏌ョ湅鎺у埗鍙扮粨鏋滃彲浠ョ湅鍒版槸涓€涓彲浠ュ姞杞藉埌鎴戜滑瀹炵幇绫讳腑鐨勬柟娉曪紝琛ㄧず宸茬粡瀹炵幇浜哠PI鐨勫姛鑳?锛夊疄鐜板師鐞嗗叾瀹炴垜浠湪涓婇潰浣跨敤SPI鐨勬椂鍊欙紝鍙互鐪嬪埌涓€涓叧閿殑绫诲氨鏄疭erviceLoader锛屽畠浣嶄簬java.util鍖呬笅銆傛垜浠洿鎺ョ偣鍑籰oad()鏂规硶锛岀湅鐪嬪浣曡皟鐢╨oad()鏂规硶鎴戜滑闀垮畼鐪嬪埌鐨勫涓嬩唬鐮併€傝浠g爜鍧楃畝鍗曞湴澹版槑浜嗙嚎绋嬩笂涓嬫枃鍔犺浇鍣ㄧ殑浣跨敤銆傛垜浠户缁窡杩汼erviceLoader.load(service,cl)銆傝繖娈典唬鐮佹病浠€涔堝ソ璇寸殑锛岃鍙ヨ繑鍥炰簡ServiceLoader瀵硅薄銆傝繖涓璞℃湁鍝簺鏂囩珷锛熸垜浠彲浠ユ煡鐪嬭繖涓被鐨勫0鏄巔ublicfinalclassServiceLoaderimplementsIterable{}鍙互鐪嬪埌杩欎釜瀵硅薄瀹炵幇浜咺terable鎺ュ彛锛岃鏄庡畠鏈夎凯浠f柟娉曘€傛垜浠彲浠ョ寽娴嬶紝杩欐槸鎶婃垜浠畾涔夌殑SPI鐨勬墍鏈夊疄鐜扮被閮芥娊鍙栧嚭鏉ヤ簡銆傝繖涓被鐨勬瀯閫犲嚱鏁板涓嬨€傞噸鐐规槸reload()鏂规硶銆傚湪杩欓噷缁х画璺熻繘锛屼竴璧锋埅鍙栬瘎璁恒€傛垜浠彲浠ョ湅鍒拌繖鍙ヨ瘽鏂规硶瀹炰緥鍖栦簡鎯版€ф悳绱紝璇存槑浜嗗疄鐜颁笂闈㈡彁鍒扮殑Iterable鎺ュ彛鐨勭敤澶勩€傛垜浠繖閲屽彲浠ュ厛鐐瑰嚮iterator()鏂规硶鐪嬬湅瀹冩槸濡備綍瀹炵幇鐨勩€傚彲浠ョ湅鍒版湁涓€涓猭ey缂撳瓨銆傜紦瀛樺瓨鍌ㄦ彁渚涜€呫€傛瘡娆℃搷浣滈兘浼氬幓缂撳瓨涓壘銆傚鏋滃瓨鍦ㄥ垯杩斿洖锛屽惁鍒欎娇鐢↙azyIterator鏌ユ壘锛屾垜浠繘鍏azyIterator绫伙紝鐪嬬湅瀹冩槸濡備綍瀹炵幇鐨勩€傜敱浜庤繖涓被鐨勪唬鐮佸お闀匡紝鎴戜滑鐩存帴鎴彇鍏抽敭浠g爜銆傛湁鍏磋叮鐨勫悓瀛﹀彲浠ヨ嚜琛屾煡鐪嬪畬鏁翠唬鐮侊細鐪嬪埌浠g爜鐨勫疄鐜拌眮鐒跺紑鏈椼€傛垜浠湅鍒颁簡鐔熸倝鐨勭洰褰曞悕META-INF/services/锛屼唬鐮佷細鍘绘寚瀹氱洰褰曡幏鍙栨枃浠惰祫婧愶紝鐒跺悗閫氳繃涓婁紶浼犲叆鐨勭嚎绋嬩笂涓嬫枃绫诲姞杞藉櫒鏉ュ姞杞界被锛岃繖鏍锋垜浠殑SPI瀹炵幇绫诲氨鍙互浣跨敤浜哹yproject~鐪嬪畬涓嶅緱涓嶆劅鍙箏鑷虫锛屾垜浠媶瑙d簡JAVASPI鐨勪娇鐢ㄥ拰瀹炵幇鍘熺悊銆傜湅瀹屾槸涓嶆槸瑙夊緱杩欎釜鎶€鏈鎴戜滑涓嶈繙浜唦锛?.鎬荤粨浣跨敤JavaSPI鏈哄埗鏇村ソ鐨勫疄鐜颁簡鍙彃鎷斿紑鍙戠悊蹇碉紝灏嗙涓夋柟鏈嶅姟妯″潡鐨勭粍瑁呬笌璋冪敤鏂圭殑涓氬姟浠g爜鍒嗙锛屽嵆瑙h€︾殑鐞嗗康銆傛垜浠殑搴旂敤绋嬪簭鍙互鏍规嵁瀹為檯涓氬姟闇€姹傝繘琛屽畾鍒躲€傛墽琛屽姩鎬佷氦鎹€?銆佹墿灞昐pringSPI褰撶劧锛孲PI鏈哄埗涓嶄粎浠呭湪JDK涓疄鐜帮紝鎴戜滑鏃ュ父寮€鍙戜腑浣跨敤鐨凷pring銆丏ubbo妗嗘灦閮芥湁鐩稿簲鐨凷PI鏈哄埗銆係pringBoot涓殑璁稿閰嶇疆鍜屽疄鐜伴兘鏈夐粯璁ゅ疄鐜般€傚鏋滄垜浠淇敼涓€浜涢厤缃紝鍙渶瑕佸湪閰嶇疆鏂囦欢涓啓鍏ョ浉搴旂殑閰嶇疆锛岀劧鍚庨」鐩氨搴旂敤鎴戜滑瀹氫箟鐨勯厤缃唴瀹癸紝鑰岃繖涓€绉嶆柟寮忓氨鏄娇鐢⊿PI鏉ュ疄鐜般€侸avaSPI鍜孲pringSPI鐨勫尯鍒獼DK浣跨敤鐨勫姞杞藉伐鍏风被鏄疭erviceLoader锛岃€孲pring浣跨敤鐨勬槸SpringFactoriesLoader銆侸DK鐨勭洰褰曞懡鍚嶆柟寮忔槸META-INF/services/provider鎺ュ彛鐨勫叏绫诲悕锛岃€孲pring浣跨敤META-INF/spring-Factories锛屽湪浣跨敤SpringBoot鏃讹紝鎴戜滑浼氬啓涓婃垜浠兂瑕佺殑绫荤殑鍏ㄧ被闄愬畾鍚嶅皢IOC瀹瑰櫒娉ㄥ叆鍒癕ETA-INF/spring.factories鏂囦欢涓€係pringBoot绋嬪簭鍚姩鏃讹紝浼氳SpringFactoriesLoader鍔犺浇锛屾壂鎻忔瘡涓猨ar鍖卌lass-path鐩綍涓嬬殑META-INF/spring.factories閰嶇疆鏂囦欢锛岀劧鍚庤В鏋恜roperties鏂囦欢锛屾壘鍒版寚瀹氬悕绉扮殑閰嶇疆骞惰繑鍥炲畠銆傛墍浠PI鍦ㄦ垜浠疄闄呭紑鍙戜腑闅忓鍙锛屼笉浠呬粎鏄疭pring锛屾瘮濡侸DBC鍔犺浇鏁版嵁搴撻┍鍔紝SLF4J鍔犺浇涓嶅悓鎻愪緵鍟嗙殑鏃ュ織瀹炵幇锛岃繕鏈塂ubbo浣跨敤SPI瀹炵幇妗嗘灦鎵╁睍绛夌瓑銆備笉瑕佽绌鸿瘽锛屼笉瑕?涓嶅伔鎳掞紝鍜屽皬鑿滀竴璧峰仛涓惞鍢榅鏋舵瀯鐨勭▼搴忕尶鍚鐐瑰嚮鍏虫敞锛屽仛浼达紝璁╁皬鑿滀笉鍐嶅鍗曘€備笅闈㈣锛佷粖澶╀綘鍔姏涓€鐐癸紝鏄庡ぉ姹備汉鐨勫彛姘斿氨灏戜竴鐐癸紒鎴戞槸灏忚彍锛屼竴涓拰浣犱竴璧峰彉寮虹殑鐢蜂汉銆傪煉嬪井淇″叕浼楀彿宸插紑閫氾紝钄″啘璇达紝娌″叧娉ㄧ殑鍚屽璁板緱鍏虫敞鍝︼紒