.NET Conf 2020 - 基于ASP.NET Core构建可热插拔的插件化系统
文章標(biāo)題:.NET Conf 2020 - 基于ASP.NET Core構(gòu)建可熱插拔的插件化系統(tǒng)
作者:Lamond Lu
項目地址:https://github.com/lamondlu/CoolCat
博客:http://www.cnblogs.com/lwqlun
以下是2020.12.19日的演講文稿和視頻:
大家好,我是陸楠,我來自北京盛安德科技發(fā)展有限公司青島分公司,很高興能參加本次.NET開發(fā)者大會,今天我分享的主題是《基于ASP.NET Core構(gòu)建可熱插拔的插件化系統(tǒng)》。
插件化架構(gòu),又稱微核架構(gòu),指的是軟件的內(nèi)核相對較小,主要功能和業(yè)務(wù)邏輯都通過插件實現(xiàn)的架構(gòu)。
插件化架構(gòu)一般有兩個核心概念:
內(nèi)核
插件
內(nèi)核通常只包含系統(tǒng)運行的最小功能,以及定義插件必須符合的接口;插件則是互相獨立的模塊,一般只包含單一的功能。
插件化技術(shù)并不是一個新興的技術(shù),早期很多基于COM開發(fā)的WIN32程序其實都是插件化的系統(tǒng)。在.NET/.NET Core中,也有許多插件化的實現(xiàn)方案,例如,開源框架ABP, 開源的內(nèi)容管理系統(tǒng)DotNetNuke, 電子商務(wù)框架NopCommerce。
在設(shè)計插件化方案的時候,我們需要考慮以下幾個問題:
如何隔離插件
如何實現(xiàn)插件之間的通訊
如何實現(xiàn)熱插拔
在.NET Framework時代,我們最常用的方案是使用AppDomain應(yīng)用程序域來封裝插件。使用AppDomain, 我們可以將不同的插件隔離在不同的應(yīng)用程序域中。至于插件與插件之間的通訊,我們可以借助MarshalByRefObject類來實現(xiàn)。至于熱插拔,我們可以通過AppDomain自帶的Load/Unload方法來完成,非常的簡單。
但是到了.NET Core中,情況大不相同了。主要的原因是.NET Core中已經(jīng)將AppDomain的概念移除了,那么我們該如何實現(xiàn)插件化呢?
這里我們首先要介紹的是ASP.NET Core中新引入的功能AssemblyLoadContext, 簡稱ALC, ALC提供了一個類似AppDomain的隔離區(qū)域,你可以通過ALC來加載程序集,每個ALC加載的程序集之間互不干擾。
這里請注意,正是由于這種設(shè)計,如果將一個程序集引入到兩個不同ALC中,運行時會認(rèn)為他們是不同的程序集。
除了自定義的ALC, 在每個ASP.NET Core應(yīng)用啟動的時候,運行時都會創(chuàng)建一個默認(rèn)的ALC, 這里我們需要了解自定義ALC和默認(rèn)ALC的加載順序
當(dāng)自定義ALC中的某個插件使用某個程序集的時候,會優(yōu)先查找當(dāng)前插件所在的自定義的ALC,如果找不到該程序集,則會進(jìn)一步查找默認(rèn)ALC, 所以ALC的程序集加載會優(yōu)先于默認(rèn)ALC
我們前面說過,不同的ALC應(yīng)用相同的程序集,運行時會認(rèn)為他們是不同的程序集,所以當(dāng)兩個插件使用相同程序集的,我們最好將這個程序集加載到默認(rèn)ALC中,否則在插件交互的時候可能會出現(xiàn)類型沖突。
除了AssemblyLoadContext, 為了實現(xiàn)插件化,微軟在ASP.NET Core中還提供了另外一個高級特性Application Part - 應(yīng)用組件。
Application Part并不算一個新特性,因為在它在.NET Core 2.x版本中就已經(jīng)被引入了,但是可能部分開發(fā)人員沒有過或了解過它。Application Part為ASP.NET Core提供了強大的復(fù)用能力,使用Application Part, ASP.NET Core可以從程序集中發(fā)現(xiàn)控制器、視圖組件、Razor預(yù)編譯視圖、Tag Helper等功能,再借助Application Part Manager, 這些已經(jīng)編譯好的功能組件就可以在其它項目中直接復(fù)用了,這就極大提高了ASP.NET Core功能組件的可復(fù)用行。
基于AssemblyLoadContext和Application Part, 你就可以輕松的實現(xiàn)ASP.NET Core的插件化了,但是如果想要在ASP.NET Core中實現(xiàn)一個可熱插拔的插件化組件系統(tǒng),我們還需要針對ASP.NET Core解決很多適配性問題,例如:
如果在運行時加載預(yù)編譯視圖?
如果在運行時刷新路由和Controler/Action的映射關(guān)系?
一個組件如何從另外一個組件拉取數(shù)據(jù)
一個組件如何向另外一個組件發(fā)送消息通知,完成進(jìn)一步的業(yè)務(wù)操作
為了簡化這一部分的復(fù)雜度,我搭建了一個開源項目CoolCat, CoolCat默認(rèn)支持.NET Core 3.1和.NET 5。
CoolCat已經(jīng)實現(xiàn)了以下的特性
插件的安裝升級
運行時熱插拔插件
插件間通訊
類Swagger的插件文檔
支持容器化
以下是CoolCat的整體架構(gòu)圖:
這里主程序為CoolCat, 所有的插件都通過ALC加載到主程序中,主程序中定義了通知中心、文檔中心、查詢中心
通知中心負(fù)責(zé)跨插件的消息通知
文檔中心負(fù)責(zé)生成插件的文檔
查詢中心負(fù)責(zé)跨插件的數(shù)據(jù)查詢
并且為了簡化創(chuàng)建插件項目,我創(chuàng)建了一個CoolCat插件模板,你可以通過dotnet new命令來安裝插件模板,并安裝模板項目。
dotnet?new?–i?CoolCatModule dotnet?new?CoolCatModule?–n?{projectName}這里創(chuàng)建出的插件項目和一個普通MVC項目相差無幾,比較特殊的是項目會自動生成一個plugin.json文件,里面包含了當(dāng)前插件的基本信息。
如果這個項目的生成文件打包,那么它就是一個可移動的插件安裝包了。
下面呢,我們就通過一個簡單的Demo, 給大家演示一下CoolCat項目的基本功能。
這里我們首先使用dotnet run命令啟動當(dāng)前CoolCat, 當(dāng)程序第一次啟動的時候,會自動建表。這里呢,我使用了FluentMigrator作為數(shù)據(jù)庫遷移工具,所以在項目啟動時,可以進(jìn)行自動的腳本遷移。
項目啟動之后,我們就可以從瀏覽器打開這個項目了。項目的默認(rèn)界面是安裝界面,我們可以在這個界面上選擇一些預(yù)定義的插件,完成安裝
當(dāng)然也不僅限于此,如果你想自定義一個其他的預(yù)安裝插件,你可以將這些插件放置在項目下的PresetModules目錄中。
這里呢,我們就選擇默認(rèn)的2個插件,完成安裝。
安裝完成之后,我們就會自動進(jìn)入CoolCat的主界面。這里我們可以通過System菜單下的Plugins子菜單來管理插件。
現(xiàn)在呢,我們來模擬一個場景,假設(shè)我們當(dāng)前開發(fā)了2個插件,一個是圖書庫存插件,一個是圖書租借插件。租借插件的數(shù)據(jù)來源是庫存插件。并且當(dāng)某本圖書從租借插件租出之后,庫存插件中的當(dāng)前圖書的狀態(tài)也應(yīng)該變?yōu)槌鰩鞝顟B(tài)。
這里我們首先通過CoolCat來安裝這2個插件。安裝完成之后,我們啟用插件,這里大家會發(fā)現(xiàn),當(dāng)我們啟動插件之后,頂部導(dǎo)航欄中會自動出現(xiàn)這個插件的菜單,這說明我們的熱插拔功能正確的引導(dǎo)并加載的插件。
下一步,我們進(jìn)入庫存插件,添加一本圖書C#, 添加完成之后,我們會發(fā)現(xiàn)這本書的默認(rèn)狀態(tài)是入庫狀態(tài)。
現(xiàn)在我們打開圖書租借功能,我們會發(fā)現(xiàn)入庫狀態(tài)的圖書,正確的顯示在了可租借圖書列表界面,這說明我們的跨插件拉取數(shù)據(jù)成功。
這時候,我們選擇租出這本書,點擊Rent按鈕,操作完成之后,這本書就從可租借列表中消失了。
下面我們回到圖書庫存插件,你會發(fā)現(xiàn)圖書庫存的狀態(tài)已經(jīng)變?yōu)槌鰩?#xff0c;這是說明我們的跨插件消息傳輸成功了,當(dāng)圖書租出之后,后續(xù)的出庫操作自動完成。
至此,我們就完成了這個簡單的Demo
如果大家感興趣的話,可以下載CoolCat項目自行體驗一下,針對整個框架的研究過程和其中遇到的問題,我都寫在了我的博客園站點中,大家可以自行查看。如果遇到問題或者想?yún)⑴c到本項目中,可以給我發(fā)郵件,也可以在博客園給我留言。
以上就是我今天分享的全部內(nèi)容,謝謝大家。
總結(jié)
以上是生活随笔為你收集整理的.NET Conf 2020 - 基于ASP.NET Core构建可热插拔的插件化系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET 云原生架构师训练营(模块二 基
- 下一篇: 【对比学习】koa.js、Gin与asp