框架怎么選 中小項(xiàng)目別踩坑)
已經(jīng)做了有幾年時(shí)間的Java后臺(tái)開發(fā)工作, 所以插件化框架這些東西真正可不是隨便找個(gè)SPI就能搞定的。今天想聊幾個(gè)在實(shí)際項(xiàng)目開發(fā)過程里碰到過的陷阱或者問題點(diǎn)。java插件化框架選型在我的這個(gè)項(xiàng)目里面, 我是使用了Maven結(jié)合自定義ClassLoader的這種處理方案的。這樣做的話, 它的整體架構(gòu)比OSGi要輕得多。其中的核心操作方式是, 我們需要把每一個(gè)單獨(dú)的插件都打包成獨(dú)立的jar包形式。然后在系統(tǒng)啟動(dòng)的過程中去掃描相應(yīng)的目錄來實(shí)現(xiàn)動(dòng)態(tài)的加載。對(duì)于類隔離這一項(xiàng)機(jī)制是如何來保證的問題, 主要是靠打破父類委托這個(gè)方式來實(shí)現(xiàn)的, 這部分內(nèi)容在文本中得到了類隔離靠打破父委托這樣的強(qiáng)調(diào)表述。在選擇技術(shù)框架的時(shí)候, 不能僅僅只是盯著文檔去看, 其實(shí)最核心的關(guān)鍵點(diǎn)是觀察這個(gè)框架具體是如何處理各個(gè)插件之間出現(xiàn)的依賴沖突問題的。我有親眼見過這么一個(gè)大項(xiàng)目實(shí)例, 當(dāng)時(shí)在該項(xiàng)目里有兩個(gè)不同的插件各自引用了不一樣版本的fastjson組件, 最終導(dǎo)致了ClassCastException異常的發(fā)生,然后開發(fā)人員足足花了一整天的時(shí)間來進(jìn)行排查和解決。java插件化熱部署方案在熱部署這個(gè)方面, 真正最靠譜的其實(shí)是用URLClassLoader替換這種辦法。具體的做法是把舊的實(shí)例里面的加載類的東西給它置空, 這樣就能讓垃圾回收機(jī)制去把它收走了。然后呢, 再去把新的jar包給重新加載一遍。對(duì)于那些說什么可以直接修改字節(jié)碼來達(dá)到效果的說法, 大家千萬別信。特別是在生產(chǎn)環(huán)境里用的時(shí)候, 絕對(duì)不要自己去折騰那些花哨的東西去弄什么熱字節(jié)碼修改。你必須把接口定義的那個(gè)操作, 嚴(yán)格地放置在插件端以及宿主端進(jìn)行共同協(xié)作的api那個(gè)包里面去, 與此同時(shí)插件端的代碼絕對(duì)不允許出現(xiàn)向宿主進(jìn)行反向依賴的這種情形, 這條規(guī)則要是稍微有點(diǎn)被破壞了這種狀態(tài)的話, 那么在卸載插件環(huán)節(jié)的時(shí)候就會(huì)直接拋出NoClassDefFoundError這個(gè)錯(cuò)誤現(xiàn)象, 然后排查起問題來那就真的是非常痛苦的狀態(tài)了。插件化這種技術(shù)在表面上看是挺簡單的, 不過真正的難點(diǎn)在于非得去把邊界給劃清楚。具體到宿主方要暴露出來什么東西、插件方面能夠去調(diào)用什么東西、以及在出現(xiàn)異常的時(shí)候要怎么去進(jìn)行兜底處理, 把這些事項(xiàng)都得定好了之后, 后面再去搞迭代開發(fā)才能不慌啊。