網絡上很多OSGi的文章上來就Activator實例,看得雲裏霧裏。要想了解OSGi,首先要知道爲什麼要用
OSGi?它有哪些好處?
首先要明確:Java缺少對高級模塊化的支持。OSGi服務平臺是專門針對Java對模塊化支持不足的情況,
由OSGi聯盟定義的一個行業標準,它引入了一個面向服務的編程模型,被稱作“VM中的SOA”
Java模塊化的不足
爲什麼說Java缺少對高級模塊化的支持?Java確實以面向對象的方式提供了某種程度的模塊化,但它從未
考慮支持粗粒度的模塊化編程。主要包括三個方面:
1. 可見性問題 / 信息隱藏
- There is no mechanism for information hiding between JARs——JAR文件直接無法實現信息隱藏。
一個Java類,可以是public,也可以是package-private;但是一個Java包呢?Java提供了很多控制可見性的
訪問修飾符,但這都是爲了解決低層面向對象封裝,而不是解決邏輯系統劃分。這就導致一個問題:如果類
要在多個包之間可見,那麼就必須是public!
- 例如,com.alpha.interface包定義了若干接口(public),com.alpha.imp包實現了這些接口
- (public);可能你只想向第三方程序暴露com.alpha.interface中的接口,但你卻無法阻止客戶端直接
- new一個實現類,因爲你也暴露了 com.alpha.imp包!
如果沒有OSGi,就不得不採用下面這種workaround:
-
爲了避免暴露非公有API,而把不相干的類放到同一個包中——損害程序的邏輯結構
而如果保持程序邏輯結構而使用多個包,則又暴露了原本不想暴露的非公有API。
2. 易錯的classpath
- There is no runtime concept that corresponds to a JAR; they are only meaningful at build-time
- and deploy-time. Once the Java Virtual Ma-chine is running, the contents of all the JARs are simply
- concatenated and treated as a single, global list: the so-called “Classpath”. This model scales very
- poorly.
- They contain no standard metadata to indicate their dependencies.
- They are not versioned, and multiple versions of JARs cannot be loaded simultaneous.
因爲classpath隱藏了代碼版本、依賴、一致性等特性,所以容易出錯!
例如,同一個項目的不同組件,依賴log4j的不同版本;則類路徑可能會強制選擇某個可能並不合適的版本,
會找到一個並不匹配的Jar,拋出NoSuchMethodError。
——是否可以通過Maven解決?
Class Loading and the Global Classpath
Java的類加載模型如下:
ClassLoader有兩個職責:
- Finding classes, i.e. the physical bytes on disk, given their logical class——如何找類,可擴展
- Transforming those physical bytes into a Class object in memory.——通過ClassLoader.defineClass
- ()實現,這個方法是native final的,不可擴展
這種模型確保了類總是會儘可能被最上層的類加載器加載。
例如我們編寫的類會被Application ClassLoader加載,該類加載器按順序查找classpath中的實體,返回第一
個匹配實體。如果classpath中找不到,則報錯ClassNotFoundException.
【總結】JRE的類加載機制是:類加載器只是簡單地在classpath中按順序查找類,並返回第一個匹配類;
JRE看到的不是一個個JAR文件,而是一個class文件列表。
- By simply searching classpath entries in order and stopping on the first match, the JRE reduces JARs
- to mere lists of class files, which are dumped into a single flat list
Conflicting Classes
Lack of Explicit Dependencies
大部分Jar都需要依賴其他Jar,但是我們如何知道這種依賴關係?
- 靠文檔描述。——不靠譜
- 靠MANIFEST.MF/Class-Path描述。——不實用,it only allows one to list further JAR files to be added
- to the classpath using absolute file-system paths, or paths relative to the file-system location
- Instead the dependency is implicit: lurking inside the class file in the JAR, ready to cause aClassNotFoundException when we try to use it.
Lack of Version Information
we need to specify a version range because depending on a single specific version of a library would make our system brittle.
考慮這麼一個場景:A.jar依賴於Log4j-1.1.jar,B.jar依賴於Log4j-1.2.jar,而Log4j其他版本都會有問題。
我們要把這兩個Log4j版本都加到classpath中,但是JRE總是隻能取到第一個jar;這樣我們要麼修改A.jar,要麼修改B.jar
-
LinkageError:例如
classpath=Log4j-1.2.jar; Log4j-1.1.jar
;後一個jar(Log4j-1.1.jar)中 - 的類都不會被加載到。但是如果後一個jar中有某個類,但是前一個jar中沒有;則這個類還是會被加載
- 到;這樣程序中會用到來自不同jar的類,可能導致LinkageError。
3. 部署和管理支持上的不足
在Java中存在對多個版本的依賴時,沒有簡單的辦法來正確部署這些代碼並執行;
部署之後也不易更新組件;
例如如果要支持動態插件機制,就需要動用類加載器(?)。
總結:JARs Are Not Modules
模塊應該具有如下三個特性:
- Self-Contained. A module is a logical whole: it can be moved around, installed and uninstalled as a
- single unit. It is not an atom — it consists of smaller parts — but those parts cannot stand alone, and
- the module may cease to function if any single part is removed.
- Highly Cohesive. Cohesion is a measure of how strongly related or focussed the responsibilities of
- a module are. A module should not do many unrelated things, but stick to one logical purpose and
- fulfil that purpose well.
- Loosely Coupled. A module should not be concerned with the internal im-plementation of other modules that it interacts with. Loose coupling allows us to change the implementation of one module without needing to update all other modules that use it (along with any modules that use those modules, and so on).
J2EE解決方案
J2EE應用服務器都具有deployment system,允許動態地部署、解部署應用,而無需重啓服務器、不會影響其他應用。
這意味着標準Java應用所使用的類加載機制是不夠用的;因爲扁平化的全局classpath會導致一個應用中的類,會很容易影響到其他應用。所以J2EE使用了一個更復雜的類加載機制:
- 如果某個類需要在EJB和WAR中共享,則其必須由EAR類加載器加載;
- 如果某個類需要在EAR之間共享,則需要由Application類加載器加載;
但是這種類就不能動態部署了,並且所有EAR都會依賴這個類,而不管是否需要。
爲了達到動態部署的目的,一般的做法是在每個EAR中分別重複部署該類。
OSGi解決方案
每個模塊都有自己獨立的classpath
OSGi類加載機制
- OSGi爲每個bundle提供一個類加載器,該加載器能夠看到bundle Jar文件內部的類和資源;
- 爲了讓bundle能互相協作,可以基於依賴關係,從一個bundle類加載器委託到另一個bundle類加載器。
優點
- 找不到類時的錯誤提示更友好。假如bundleE不存在,則bundleC就不會被解析成功,會有錯誤消息提示爲何未能解析;而不是報錯ClassNotFoundException或NoClassDefFoundError。
- 效率更高。在標準Java類加載模型中,總是會在classpath那一長串列表中進行查找;而OSGi類加載器能立即知道去哪裏找類。
解決模塊化問題
- OSGi可以幫助你先確保代碼滿足依賴關係,然後才允許執行代碼;避免類路徑錯誤
- OSGi會對類路徑上的依賴集進行一致性檢查(如:版本);
- 不必擔心由於層次化的類加載模式隱含的限制;——何種限制?
- OSGi可以把程序打包邏輯上獨立的JAR文件,並且只部署指定的部分、動態部署;——OSGi生命週期層實現動態部署
- OSGi可以聲明JAR中的哪些代碼可以被其他JAR訪問,強化可見性; ——OSGi中,只有那些被顯式導出的包才能被其他bundle使用。也就是說默認情況下,所有包都是bundle private的,不能被其他包看到。
- OSGi爲程序定義了一個插件式的擴展機制。
- In OSGi, only packages that are explicitly exported from a bundle can be imported and used in another bundle. Therefore all packages are “bundle private” by default, making it easy for us to hide the internal implementation details of our bundles from clients.
- 轉自:http://blog.csdn.net/vking_wang/article/details/12379333