2011年4月25日 星期一

Java ClassLoader & OSGi ClassLoader

Java的classLoader在程式啟動之後,主要會有三個:Bootstrap Loader、ExtClassLoader與AppClassLoader。

Delegation Model
The class loaders are hierarchical in nature, they use delegation model when loading the class.
當classloader有類需要載入時先讓其parent搜尋其搜尋路徑幫忙載入,如果parent找不到,在由自己搜尋自己的搜尋路徑載入,如果自訂ClassLoader沒有改寫 loadClass method 的情況下,只有在一個 class 尚未被載入過,且parent class loader 也無法載入指定的 class,才會使用到 findClass method。
可參考:
Java Classloader Wiki
Understanding Java Classloaders
解讀ClassLoader


OSGi最常碰到的問題就是ClassLoader,OSGi中的每個Bundle 都有一個獨立的Class Loader,Bundle 之間通過不同的ClassLoader和在MANIFEST.MF 文件中定義的條件達到class的共享。


bundle之間類的共享:

通過export package的方式實現的,在bundle的manifest中通過制定export package的方式將特定的package與其他的bundle共享。

而引用其他bundle所暴露的package有兩種方式,第一是通過import package的方式,第二種是通過required bundle的方式

OSGi容器為每個Bundle建立不同的classloader,因此每個Bundle能訪問位於下列位置中的class:
a) 位於Java啟動classpath下的、所有以Java.*開頭的package class;
b) 位於OSGi框架classlpath下的class,通常有一個獨立的classloader負責加載框架的實現類及關鍵的interface class;
c) 位於Bundle空間中的class,這些類通常包含在與Bundle相關的jar文件中,以及加到這個Bundle中的其它jar包中的class。
d) import package中的class

實際運行環境中,Bundle 的Class Loader 根據如下規則去搜索類資源:
1:如Class Resource 屬於java.* 包,則將加載請求委託給父加載器
2:如Class Resource 定義在OSGi 框架中啟動委託列表(org.osgi.framework.bootdelegation)中,則將加載請求委託給父加載器
3:如Class Resource 屬於在Import-Package 中定義的包,則框架通過Class Loader 依賴關係圖找到導出此package的Bundle 的Class Loader,並將加載請求委託給此Class Loader
4:如Class Resource 屬於在Require-Bundle 中定義的Bundle,則框架通過Class Loader 依賴關係圖找到此5:Bundle 的Class Loader,將加載請求委託給此Class Loader ;
6:Bundle 搜索自己的類資源( 包括Bundle-Classpath 裡面定義的類路徑和屬於Bundle 的Fragment 的類資源)
7:若類在DynamicImport-Package 中定義,則開始嘗試在運行環境中尋找符合條件的Bundle 。

下圖是一個簡單的osgi classloader :

然後這個是一個完整的osgi classloader




建立一個Spring Dm bundle , 設定bean Start() method
<bean id="actavitor" class="com.my.loader.internal.Actavitor"
  init-method="start" destroy-method="stop">
</bean>

Actavitor.java
public void start() throws Exception {
  System.out.println("Hello Spring OSGi World!! ");
  System.out.println("class->"+this.getClass());
  System.out.println("classLoader->"+this.getClass().getClassLoader());
  System.out.println("classLoader.getParent->"+this.getClass().getClassLoader().getParent());
  System.out.println("classLoader.getParent.getClass->"+this.getClass().getClassLoader().getParent().getClass());
  
  System.out.println("applicationCtx.getClass ->"+applicationCtx.getClass());
  System.out.println("applicationCtx.getClassLoader ->"+applicationCtx.getClassLoader());
  System.out.println("applicationCtx.getClassLoader.getClass ->"+applicationCtx.getClassLoader().getClass());
  
 }

Result
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        Hello Spring OSGi World!!  
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        class->class com.my.loader.internal.Actavitor 
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        classLoader->KernelBundleClassLoader: [bundle=com.my.loader.BundleClassLoaderTester_1.0.0] 
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        classLoader.getParent->org.eclipse.osgi.launch.EquinoxFWClassLoader@1d77d9e 
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        classLoader.getParent.getClass->class org.eclipse.osgi.launch.EquinoxFWClassLoader 
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        applicationCtx.getClass ->class org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext 
[2011-04-25 13:39:26.093] region-dm-11                 System.out                                                        applicationCtx.getClassLoader ->BundleDelegatingClassLoader for [Spring OSGi Bundle (com.my.loader.BundleClassLoaderTester)] 

Eclipse Virgo 的Bundle ClassLoader 為KernelBundleClassLoader
而KernelBundleClassLoader的parent為EquinoxFWClassLoader

Spring DM 會為每個bundle建立ApplicationContext , classloader透過BundleDelegatingClassLoader
BundleDelegatingClassLoader部份代碼
private final ClassLoader bridge;
.
.
/**
  * Private constructor.
  * 
  * Constructs a new <code>BundleDelegatingClassLoader</code> instance.
  * 
  * @param bundle
  * @param bridgeLoader
  */
 protected BundleDelegatingClassLoader(Bundle bundle, ClassLoader bridgeLoader) {
  super(null);
  Assert.notNull(bundle, "bundle should be non-null");
  this.backingBundle = bundle;
  this.bridge = bridgeLoader;
 }

 protected Class findClass(String name) throws ClassNotFoundException {
  try {
   return this.backingBundle.loadClass(name);
  }
  catch (ClassNotFoundException cnfe) {
   DebugUtils.debugClassLoading(backingBundle, name, null);
   throw new ClassNotFoundException(name   " not found from bundle ["   backingBundle.getSymbolicName()   "]",
    cnfe);
  }
  catch (NoClassDefFoundError ncdfe) {
   // This is almost always an error
   // This is caused by a dependent class failure,
   // so make sure we search for the right one.
   String cname = ncdfe.getMessage().replace('/', '.');
   DebugUtils.debugClassLoading(backingBundle, cname, name);
   NoClassDefFoundError e = new NoClassDefFoundError(name   " not found from bundle ["
       OsgiStringUtils.nullSafeNameAndSymName(backingBundle)   "]");
   e.initCause(ncdfe);
   throw e;
  }
 }
.
.
.
.

OSGi classLoader basic有提到 DefaultClassLoader. To get the allocated Bundle of a DefaultClassLoader we can call the getDelegate() Method.SpringDm 裡的BundleDelegatingClassLoader有設定bridge classloader, class loader adapter..主要還是透過org.osgi.framework.Bundle 的classloader來取的每個Bundle 的classloader。


Reference:
Basics about OSGi Classloading
http://codescale.wordpress.com/2009/05/22/basics-about-osgi-classloading/


Class Loader Architecture Comparison – Java, J2EE and OSGi
http://shylendrabhat.com/blog/2009/11/21/class-loader-architecture-comparison-java-j2ee-and-osgi/

classloader相關基礎知識
http://www.iteye.com/topic/25053

探索OSGi 框架的組件運行機制
http://www.ibm.com/developerworks/cn/java/j-lo-osgi/

深入了解Java ClassLoader、Bytecode 、ASM、cglib
http://www.iteye.com/topic/98178
http://blog.csdn.net/chief1985/archive/2009/08/12/4440398.aspx

沒有留言:

張貼留言