天天看點

Pandora Boot

Pandora Boot是在Pandora的基礎之上,發展出的更輕量地使用Pandora的一種方式。

  • Pandora Boot基于Pandora和Fat Jar技術,可以直接在IDE裡啟動Pandora環境,大大提高您的開發調試效率。
  • Pandora Boot與Spring Boot AutoConfigure深度內建,讓您同時可以享受Spring Boot架構帶來的便利。

基于Pandora Boot來開發部署在EDAS上的應用,适用于需要使用HSF的Spring Boot使用者以及已經使用過Pandora Boot的使用者。

在阿裡集團内部,幾乎所有的應用都用到了各式各樣的中間件,比如HSF、TDDL、Diamond等等。本身中間件之間可能就有版本依賴的問題,比如你的應用HSF和Diamond分别依賴了同名jar包的不同版本,maven隻會引入其中一個版本。同樣的中間件和應用之間也存在同樣的Jar包依賴的問題,出于要解決這些依賴沖突的問題,阿裡就開發了Pandora ,中文名潘多拉,簡單的來說就是一個類隔離容器。

Pandora要解決的問題:

1. 二方包、三方包沖突:NoSuchMethodError

如果不采用類隔離,則應用依賴的所有外部類都植入到CLASSPATH下,都由AppClassLoader進行加載。假設類A依賴類B (version 1),類C依賴類B (version 2),并且使用了B (version2)中的一個新方法,如果此時AppClassLoader加載的是B(version),就會獲得成就“NoSuchMethodError”。依賴管理工具Maven給出的解法是,手動将B(version1)排除,它會導緻應用起不來。

2. 沖突排查浪費大量時間

試想,如果我們應用系統依賴的中間件逐漸增多時,排除包将是一件很恐怖的事情!那麼中間件團隊可能就要花大量時間在答疑上面,和應用開發一起折騰了。

可怕的遠遠不止此,排除好了,應用系統也跑起來了,但到了某個點某個場景可能就出bug了。

3.中間件更新困難

如果要實時更新中間件到推薦版本,但是發現并沒有那麼容易,應用中引入了十個八個中間件,隔三差五其中一個中間件就有小版本更新,每天盯着中間件的更新情況,那還有時間關心業務的開發了。

那Pandora要解決什麼問題:

  • 實作類隔離,提供穩定的運作環境,Pandora實作了應用與中間件之間隔離、中間件與中間件之間隔離,保證了類的正确加載,而不會讓依賴關系與依賴加載出現不一一對應的情況。
  • 中間件平滑更新,由于應用伺服器會優先加載Pandora的類,是以隻要更新Pandora中的插件即可,無需對應用中的pom.xml進行修改。
  • 中間件統一管理,降低中間件接入和使用成本,Pandora會統一管理中間的啟動、初始化以及資源回收等一系列操作,開發者基本上隻需要了解它的配置及使用特性就好

設計上要滿足:

  • 類加載器隔離,Pandora容器本身和應用之間隔離
  • 中間件插件化,定義标準的啟動、導出方式和使用方法
  • 內建到spring ioc,減少提供優化的API降低使用成本

Pandora Boot

Pandora Boot是在Pandora的基礎之上,發展處的更輕量使用集團中間件的方式;它基于Pandora和FatJar基礎,可以可以在IDE裡啟動Pandora環境,開發調試等效率大大提高。也就是Pandora Boot是Pandora與Spring Boot結合的産物,可以更友善的享受Spring Boot社群帶來的便利。

Pandora Boot與Spring Boot的聯系和差別

兩者差別:

  • Spring Boot 通過 Maven 來管理依賴,是平闆化的,最前面提到的二方包、三方包依賴問題,SpringBoot解決不了
  • Pandora Boot很好的管理了中間件應用,使用者可以快速的引入各類中間件,平滑的保持中間件更新。
  • Pandora Boot 目前已經很好的內建了 autoconfig,外部也和 AONE2、PSP 等系統進行打通,開發起來更加的友善

關于啟動原理

下圖要結合内部元件圖進行了解(生成的可運作的jar解壓)會發現差別:Main-Class被替換成Pandora Boot的!

Pandora Boot

下圖是spring boot的其實就是maven plugins的spring-boot-loader-tools把spring-boot-loader.jar打進去了。

Pandora Boot

Pandora Boot原理也是,它複雜點最終呈現的是spring-boot-loader.jar和pandora-boot-loader.jar。

Pandora Boot

OSGI

前景

  • 可插拔的系統,部分的路由器都支援子產品的熱插拔,硬體界的這種熱插拔技術一直就是軟體界所追求的,而 OSGI則使得熱插拔技術在軟體界成為現實。
  • 可動态改變行為的系統,在業界可插拔的系統其實并不少,但可動态改變行為的系統并不多,,OSGI 有一整套完整的機制去實作動态改變系統行為。
  • 穩定、高效的系統,基于OSGI的系統采用的是微核機制,微核機制保證了系統的穩定性,微核機制的系統隻要微核是穩定運作的,那麼系統就不會崩潰。
  • 規範的、可積累的子產品,為什麼大部分軟體公司都形成不了規範的子產品開發方式呢?因為沒有統一的規範的基礎架構體系的定義,往往每個項目、每個産品都會因為架構師的偏好、技術的發展而導緻子產品的開發方式完全不同,這就使得軟體公司在人員技能要求、培養上很難形成統一,而 OSGI 為這個問題提供了解決方案,基于 OSGI 的系統采用規範的子產品開發、部署方式建構系統。當然,采用 OSGI 作為規範的子產品開發、部署方式自然給現有梯隊提出了新的要求,對于設計師而言,需要學習新的基于 OSGI 的子產品分解、設計方式,對于開發人員而言,需要學習新的基于 OSGI 的開發方式,但對于公司形成規範的子產品開發方式能帶來的回報而言,這樣的付出是值得的,而且,這個學習成本并不是很高。

名詞解釋

 Bundle

Bundle其實就是一個jar檔案,這個jar檔案和普通的jar檔案唯一不同的地方就是Meta-inf目錄下的MANIFEST.MF檔案的内容,關于Bundle的所有資訊都在MANIFEST.MF中進行描述,說的時髦點,可以稱它為bundle的中繼資料,這些資訊中包含有象Bundle的名稱、描述、開發商、classpath、需要導入的包以及輸出的包等等。

 Service

一個OSGI Service就是注冊到OSGI架構中的一個java對象。在注冊時可以設定這個Service的屬性。而在擷取Service的時候可以根據屬性進行過濾(Filter)。Bundle可以通過Bundle的上下文去注冊Service或去查詢Service。

Service-Oriented Component Model

簡稱面向服務的元件模型,提出為了不通過代碼的方式注冊和擷取服務的執行個體,而Delareative Service就能夠使我們夢想成真。

Declarative Service

簡稱聲明式服務或DS容器,對OSGI服務層提出的一直标準(可以看DI Container的影子)。OSGI的發展恰逢2005 SOA風潮最盛,目标是建立一個向後相容的、記憶體可控的、可延遲服務激活的、使用配置來代替編碼并消除平台侵入的新服務管理模型。

是以在OSGI R4 的重大改進,它對OSGI 的 Core Framework 進行了完善和提升,在 OSGI Core Framework對于系統采用的是 Module+Service的開發方式 ,但按照分結構的開發方式而言,系統按照的是 Module 分解為 Component+Service。

Component

定義(和Service 定義差不多)


對外提供 Service;
使用其他 Component 提供的 Service;
交由 OSGI 架構管理生命周期;      
類型


Immediate:立即激活;
Delayed:延遲激活;
Factory:與Immediate基本相同隻有在調用 ComponentFactory 的newInstance後才會激活裡面的各個元件      
引用政策(設定policy屬性)


Static:預設的方式,在 Component 啟動後,如果引用的 service 發生變動時,整個Component會重新開機;
Dynamic:而采用 dynamic 政策的情況下,在 Component 啟動後,如果引用的 service 發生變動,并不會導緻整個 Component 重新開機,而隻會調用其中的 unbind和 bind 方法。      

Service Hook

簡稱服務鈎子,是開發人員幹預Osgi架構和具體服務間互動過程的工具,R4.2版正式列入Osgi規範。本質上也是一個Osgi服務,提供了觀察和空值服務系統資料庫的相關操作,可以限定某個事件可以被那些Bundle接受到,也可以限定某個Bundle可以申請到哪些服務的應用。必須實作 org.osgi.framework.hooks.service.EventListenerHook 接口。

Pandora Boot

ServiceFactory

無論多少個Bundle請求這個服務,擷取的的服務對象執行個體都是同一個,也就是說這個服務是單例的,OSGI中預設的服務就是單例服務,服務對象中跟所有的方法都保持了無狀态性。很多時候我們有這樣的需求,服務的延遲建立(真正使用服務的時候再建立),無法滿足。是以提出了服務工廠。通過implements ServiceFactory<T>來完成。

注:服務工廠傳回的“多例”是相對于多個Bundle調用而言的,即多個Bundle多個執行個體。在同一個Bundle中,Osgi容器對服務工廠的傳回結果做了緩存,即使多次調用傳回的仍然是同一個執行個體。

ServiceTracker

服務追蹤器,如果系統使用了成百上千個服務,為了解決這些服務的互相依賴而去調配啟動級别是一件非常可怕的工作,沒有人願意幹這個事情。更何況,OSGI是天然的動态化執行環節,為了不讓服務的使用者感到迷惑和複雜,需要一個能夠持續追蹤服務可用性的解決方案代替使用者去處理服務可用性的問題。

需要導入org.osgi.util.tracker,建立一個類implements ServiceTrackerCustomizer,完成addingService、modifiedService、removedService方法的重寫。

ServiceReference

引用服務,有的同學會注意到我們從BundleContext、ServiceReference和ServiceTracker中擷取服務引用,将其存放至方法的局部變量中,在方法結束時随方法的棧幀一起銷毀。為什麼呢?另外Osgi設計的服務引用架構為什麼每次使用服務都花費一次查詢服務的開銷?之是以這樣設計,主要是考慮到自身動态執行環境,服務在Osgi環境中随時都可能被停用。

如果長期持有服務執行個體會有什麼後果呢?當服務提供方的這個Bundle被停止後,服務引用依然是有效的,執行這個執行個體的接口不會報錯的,當然這點也并不神秘,它隻是一個普通的java對象,存在引用的java對象不可能自動銷毀。更可怕的事情是,它的接口、實作類、實作類中引用的其他類以及加載這些類的類加載器都無法被垃圾回收器回收,當Bundle多次更新後,很可能形成記憶體洩露。

設計理念

由于基于 OSGI 搭建系統帶來的是架構級别的改變,帶來的最大的影響莫過于設計層面,同時對于系統開發和部署也産生了影響。

子產品化設計

盡管大家在設計大部分的系統時候确實是按照子產品化的思想去進行的,但可能不會考慮的象 OSGI 定義 Bundle那麼的清晰,但這點相信大家都能很快的适應,畢竟子產品化的思想大緻仍然是相同的,基于 OSGI 就可以按照統一的标準進行子產品的設計,同時也會提升在子產品設計時對于子產品的輸入(依賴)  、輸出(功能) 、擴充的關注,進而使得子產品的設計更加的完善和規範。

因為OSGi中的子產品化是實體隔離的,而不基于OSGi的話很難做到實體隔離方式的子產品化實作,也就很難使系統真正的做到子產品化,通常切換到基于OSGi後就會發現以前的子產品化設計做的還是很不足。基于OSGi進行子產品化的設計時和傳統做設計時的子產品設計并沒有多大的差别,均為定義子產品的範圍、子產品對外提供的服務和所依賴的服務。

面向服務的元件模型設計

面向服務的元件模型的設計思想是OSGi的核心設計思想,推崇系統采用Bundle的方式來劃分,Bundle由多個Component來實作,Component 通過引用Service 或暴露 Service 來完成子產品中用例的實作。應該說,這種基于OSGi實作的系統自然就是符合 SOA 體系架構的。

面向服務的元件模型設計更加強調在設計時分解子產品中用例的實作(形成元件和服務)以及元件依賴的關注。基于 OSGI 架構構模組化塊、Component、Service 的依賴時,展現出了超越傳統 IoC 容器的優勢,在依賴的建構上 OSGI 更是提供了多種靈活的依賴控制方式,例如屬性過濾、版本過濾以及延遲加載設定等。

在OSGi中Component以POJO的方式編寫,通過DI的方式注入其所引用的服務,以一個标準格式的 XML 描述 Component 引用服務的方式、對外提供的服務以及服務的屬性。

動态性設計

要充分的發揮基于 OSGI 的動态性,就要完全的采用面向接口的設計方式,而不是去依賴實作,要記住基于 OSGI 搭建的系統是在運作期才構成依賴的,這和傳統的系統有很大的差别,應該在運作期由 OSGI 架構自動的注入。OSGI 提供的對于依賴的各種管理政策(如版本過濾、多樣性設定等)在保證系統動态性的同時也保證了系統擷取到所需的子產品、Component或Service。

在設計時要記住的是所依賴的OSGi服務或Bundle都是有可能動态的解除安裝或安裝的。為保持系統的動态性,在設計時要遵循的原則是不要靜态化的依賴任何服務,避免服務不可用時造成系統的崩潰,另外保證系統的“即插即用,即删即無”。

可擴充的設計

OSGi在設計時提倡采用可擴充式的設計,即可通過系統中預設的擴充點來擴充系統的功能。有兩種方式來實作:

  • 引用服務的方式

通過在元件中允許引用服務接口的多個實作來實作元件功能的不斷擴充,例如A元件的作用為顯示菜單,其通過引用菜單服務接口來擷取系統中所有的菜單服務,此時系統中有兩個實作此服務的元件,分别為檔案菜單元件和編輯菜單元件,那麼 A元件相應的就會顯示出檔案菜單和編輯菜單,而當從系統中删除編輯菜單的元件時,A元件顯示的菜單就隻剩檔案菜單了,如此時再部署一個實作菜單服務接口的視圖菜單元件子產品到系統中,那麼顯示出來的菜單則會為檔案、視圖。

  • 定義擴充點的方式

按照 Eclipse 推薦的擴充點插件的标準格式定義 Bundle 中的擴充點,其他需要擴充的 Bundle 可通過實作相應的擴充點來擴充該 Bundle的功能。

面向接口的開發

OSGI 提供為每個 Bundle 提供獨立的 ClassLoader 機制的方法則讓我們可以真正的做到面向接口的開發。

OSGI R4

OSGI R4 規範由 Framework、Standard Services、Framework Services、System Services、Protocol Services、Miscellaneous Services 共同組成,在規範中對以上的各個方面進行了詳細的介紹和規定,在這個章節中會深入的介紹 OSGI R4 中的關鍵部分,同時結合理論對之前的使用者登入驗證子產品的實作進行講解和改善。

Core Framework

Pandora Boot
Pandora Boot
Pandora Boot

Module Layer

在OSGI規範中,将Module命名為Bundle,是以,在OSGI架構中是采用Bundle的方式來組織和部署系統的。包含:

  • Module的定義:定義MANIFEST.MF的中繼資料資訊;
  • Module的package共享機制:包含Export-Package、Import-Package、Dynamic Imports(差別在于OSGI架構在resolve Bundle時就不會對其import的package做檢測,到使用是才去擷取);
  • Module的Classloader機制;
  • Module的國際化;
  • Module的校驗;
  • 三種特殊形式的Bundle:包含Require Bundles、Fragment Bundles、Extension Bundles。

Bundle 的通訊機制

Bundle之間通過Service和Packages兩種方式來進行通訊。Packages方式是通過定義Bundle的Import-Package和Export-Package來實作,Service機制可以實作引用其他 Bundle 中提供的類的執行個體。

Pandora Boot

Bundle事件監聽

Pandora Boot

LifeCycle Layer

Lifecycle Layer基于Module Layer,使得基于OSGI架構可以動态的對Bundle的生命周期進行管理。 

包含Bundle的狀态、管理Bundle的狀态、監聽Bundle的狀态。

Bundle的狀态

INSTALLED:Bundle已經成功的安裝了。
RESOLVED:Bundle中所需要的類都已解析好,可啟動或者說 Bundle 已被停止。
STARTING:Bundle正在啟動中,BundleActivator的start方法已經被調用,但沒傳回。
ACTIVE:Bundle已啟動,并在運作中。
STOPPING:Bundle正在停止中,BundleActivator的stop方法已經被調用,但沒傳回。
UNINSTALLED:Bundle 已經被解除安裝。      

監聽Bundle的狀态

在監聽 Bundle 的狀态上 OSGI 采用的是典型的 Java 中的事件機制,在 OSGI中事件分為 Framework Event和 Bundle Event 兩種,Framework Event 用于報告 Framework 已啟動、改變了 StartLevel、重新整理了 packages或是出現了錯誤;而 Bundle Event 則用于報告 Bundle 的生命周期的改變。可通過實作BundleListener或SynchronousBundleListener來監聽Bundle Event,可通過實作 FrameworkListener來監聽 Framework Event。

Pandora Boot

Service Layer

Service Layer定義了Bundle 動态協作的服務釋出、查找和綁定模型,Service Layer基于 Module Layer和 Lifecycle Layer,使得 OSGI 形成了完整的動态模型。包含:

  • 服務的注冊;
  • 服務的擷取;
  • 服務的監聽

可以實作ServiceListener可監聽Service的狀态,推出Declarative Services之後,Service Layer其實就已經成為雞肋了,Declarative Services提供了更好的服務注冊、擷取、監聽等方式,使得其成為了OSGI R4 中的重要角色,并由此替代了Service Layer。

Service事件監聽

SeviceEvent的枚舉值

Pandora Boot

服務層的所有事件分派都是同步的,OSGI規範定義了ServiceListener接口的ServiceChanged方法來實作監聽服務編号時的執行邏輯。其實服務追蹤器能感覺添加和移除的編号,就是依賴這個完成的。ServiceTracker的内部類Tracked和AllTracked就是實作了ServiceListener接口,它的open()和close()方法分别調用了BundleContext.addServiceListener和BundleContext.removeServiceListener。

釋放和登出服務

 釋放服務是指服務使用者聲明自己已經不再需要使用該服務對象的行為,服務提供者在OSGI架構注冊了服務後,架構會使用引用計數的方式來跟蹤服務對象執行個體是否被使用及被多少處使用。使用BundleContext.getService()申請服務時,計數器值+1,服務使用完後,通過BundleContext.ungetService(),計數器值-1。

登出服務的本質是把OSGI的服務從系統資料庫中異常,當被移除後,與該服務相關的ServiceReference對象就失效了(不是絕對的,請看ServiceReference)。

注:一定要注意儲存良好的習慣,否則會出現垃圾回收一直無法被回收的問題。

Security Layer

Security Layer在 OSGI 中采用的主要是 java 本身的 security政策和數字簽名政策。

StartLevel Service

StartLevel Service 是 OSGI 規範中的核心服務,是 OSGI 架構必須實作的服務,通過 StartLevel Service 可以動态的設定和改變 Bundle 的啟動順序, OSGI 架構在啟動Bundle 時按照啟動順序和 Bundle ID的倒序來啟動系統。

  • 靜态設定:config.ini設定 osgi.bundles.defaultStartLevel 的值來改變 Bundle 的預設啟動級别
  • 動态設定:import org.osgi.service.startlevel

onfiguration Admin Service

Configuration Admin Service 是 OSGI 中非常重要的一個服務,它用于動态的管理Bundle 的配置的屬性,而這些屬性的存儲可能是在本地、也有可能是在遠端、甚至可能會在某些裝置上,基于 Configuration Admin Service 就可以統一的、動态的、遠端的完成 Bundle 配置屬性的管理工作了。

Event Admin Service

OSGI提供了Event Admin Service以友善開發人員實作自定義的事件釋出和事件處理,和 Java的事件處理模型基本是一緻的。事件釋出者通過調用 Event Admin Service 的 sendEvent 或postEvent 方法對外釋出事件,事件訂閱者則通過實作 Event Handler并注冊為 EventHandler的服務來訂閱感興趣的事件。

OSGI R5

OSGi Bundle Repository(OBR)

Repository服務規約中提出的,就是OSGI的Bundle倉庫,和maven類似都是元件參考,Apache Felix是OBR的一種實作,簡化Bundle的部署和使用,另一方面也鼓勵了獨立Bundle的開發,OBR是以得功能都存在用戶端,用戶端隻需要OBR的xml格式元檔案就可以工作。這個檔案定義了資源、依賴關系、源碼位置、Bundle的位置資訊。

Subsystems 服務規約

日益龐大的程式以及顯得有些力不從心了,Osgi R5提出一個全新的、面向一組Bundle集合的管理系統和聲明周期模型。

服務目标要解決的是資源隔離、資源共享、運作期動态變化等問題,站在戰略層面上看為日OSGI in Clould做準備。