equinox環境下開發bundle不需要引入java.*包而需要引入javax.*包的的原因
ClassLoader(類加載器)是Java提供的抽象類,它是負責加載類的對象。ClassLoader 做的工作就是在JVM 中將類裝入內存。 當 JVM 需要使用類時,它根據名稱向 ClassLoader 請求這個類,然后 ClassLoader 返回一個表示這個類的 Class 對象。
一、前提知識 ClassLoader
ClassLoader(類 加載器)是Java提供的抽象類,它是負責加載類的對象。ClassLoader 做的工作就是在JVM 中將類裝入內存。 當 JVM 需要使用類時,它根據名稱向 ClassLoader 請求這個類,然后 ClassLoader 返回一個表示這個類的 Class 對象。
所有java.*包內的類都是由ClassLoader完成加載的,而且在執行java命令的時候ClassLoaer就已經被裝入內存中。通常在開發過程中使用java.*包內的類的時候,不再需要import 這些類了。
二、Bundle中的ClassLoader
在equinox環境下,每一個bundle都有獨立的classLoader,對應的類名為BundleLoader。
每個bundle的classLoader都有parent,這個parent(父classLoader)就是類的委派模型中的上一層的classLoader。對應的類名為ParentClassLoader,它是這樣定義的
protected ParentClassLoader() {
super(null);
}
}
這是一個空的classloader,它直接繼承了java.lang.ClassLoader 。java包中的所有類都是由java.lang.ClassLoader載入的,根據類的委派模型可以知道,繼承了ClassLoader就可以直接獲得需要的java類。
// 1) if startsWith "java." delegate to parent and terminate search
// we want to throw ClassNotFoundExceptions if a java.* class cannot be loaded from the parent.
return parent.loadClass(name);
上面代碼是bundle加載class的流程圖中的第一步,通過parentClassLoader獲得所需java.*包中的類,如下圖所示。
這就是bundle中不需要引入java.*包的原因。
三、如何知道java.*這些類已經被裝載了呢?
1、寫一個類如下:
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
2、編譯

3、運行

顯示的部分內容如下:
[Loaded java.io.Serializable from shared objects file]
[Loaded java.lang.Comparable from shared objects file]
[Loaded java.lang.CharSequence from shared objects file]
[Loaded java.lang.String from shared objects file]
[Loaded java.lang.reflect.GenericDeclaration from shared objects file]
[Loaded java.lang.reflect.Type from shared objects file]
[Loaded java.lang.reflect.AnnotatedElement from shared objects file]
[Loaded java.lang.Class from shared objects file]
[Loaded java.lang.Cloneable from shared objects file]
[Loaded java.lang.ClassLoader from shared objects file]
... (后面還有很多,不一一列舉)
四、為什么需要引入javax.*包
下面的代碼是另一篇文章 equinox實現Class Loader機制的代碼解讀 提過的,bundle類載入的流程圖片段代碼。
String pkgName = getPackageName(name);
// follow the OSGi delegation model
if (checkParent && parent != null) ...{
if (name.startsWith(JAVA_PACKAGE))
// 1) if startsWith "java." delegate to parent and terminate search
// we want to throw ClassNotFoundExceptions if a java.* class cannot be loaded from the parent.
return parent.loadClass(name);
else if (isBootDelegationPackage(pkgName))
// 2) if part of the bootdelegation list then delegate to parent and continue of failure
try ...{
return parent.loadClass(name);
} catch (ClassNotFoundException cnfe) ...{
// we want to continue
}
}
...
從上面的代碼可以看出,如果不是第一種情況(包名不是以java.開始的)就使用第二個判斷條件。
isBootDelegationPackage(pkgName)返回的是true(這個配置在以后再說),所以執行的是
parent.loadClass(name);
這 行代碼和第一個條件的代碼是一樣的,即還是使用parentClassLoader去加載javax.*的包。由于ClassLoader只加載了 java.*的包,所以這里是不能得到javax.*包中的類的,會導致 ClassNotFoundException 的錯誤。從上面的代碼可以知道,代碼中對ClassNotFoundException 沒有處理,而是 繼續執行了。分別從import package、required bundles、bundle內部classpath和dynamic import 獲取javax.*的包。
通常情況下,這些javax.*的包作為required bundle提供,而且只需要提供一次,并避免在其他的bundle中再次/重復提供(export)。
// 3) found import source terminate search at the source
result = source.loadClass(name);
if (result != null)
return result;
throw new ClassNotFoundException(name);
}
// 4) search the required bundles
source = findRequiredSource(pkgName);
if (source != null)
// 4) attempt to load from source but continue on failure
result = source.loadClass(name);
// 5) search the local bundle
if (result == null)
result = findLocalClass(name);
if (result != null)
return result;
// 6) attempt to find a dynamic import source; only do this if a required source was not found
if (source == null) {
source = findDynamicSource(pkgName);
這就是需要引入javax.*包的原因。
posted on 2008-05-05 10:26 gembin 閱讀(973) 評論(0) 編輯 收藏 所屬分類: OSGi