OSGI的核心可以说就是它的类加载机制。在OSGI 容器内不同的Bundle可以共享同一个Java虚拟机。在同一个虚拟机中,Bundle可以对其他Bundle隐藏package或者class,当然也可以将package共享给其他的Bundle。
隐藏或者共享Java package给其他Bundle的关键机制就是类加载器从Bundle空间按规则定义的类的子集中加载类。每一个Bundle都会有自己的类加载器。
类加载器从如下的类路径中加载类和资源:
http://yanfei30.spaces.msn.com/ 类空间的所有类对于一个Bundle来说都是可以访问的。为了防止出现同一个类空间出现两个相同类名(fully qualified name)的类,然而OSGI平台分离的类空间可能会出现两个相同类名的类。因此,OSGI的Module层具有不同版本的类存在于同一个Java虚拟机中的机制。
在一个Bundle被加载之前,OSGI Framework对Bundle的manifest.mf文件进行解析,并在importer和exporter之间建立配线(wired),配线(wired)实际上就是importer和exporter之间的连接。一个配线(wired)同在menifest文件中定义的importer、exporter的限制相关。一个有效的配线(wired)必须满足所有的限制。这些限制包括版本限制、包限制、属性限制、和Bundle的提供者限制。在建立配线时,OSGI Framework会根据这些限制来选择最合适的类加载。
Bundle在OSGI Framework中安装后,并不会立即创建一个Bundle的类加载器,只有当Bundle处于resolved状态后才会创建一个类加载器,Bundle的Fragment是不会立即创建一个类加载器的,只有当该Fragment被使用时才会创建类加载器。
当一个Bundle的类加载器加载类或者查找资源时必须遵循下面的顺序:
1. 如果类或者资源在java.*包内,该请求会被委托给父类加载器。否则,继续下面步骤的查找。如果请求委托给父类加载器,并且该类或资源没找到,则查找结束并且请求失败。
2. 如果查找的类或资源在boot delegation列表内(org.osgi.framework.bootdelegation),请求会被委托给父类加载器,如果类或资源没找到,则查找结束。
3. 如果查找的类被Import- Package导入或者在早先的加载中被动态导入,则请求被分发给exporting bundle’s class loader。
4. 如果查找的类被Require-Bundle导入,该类在其他的Bundle内,则请求被分发给其他Bundle的类加载器。
5. 在bundle的内部类加载器中进行查找,如果类或者资源没有找到,则继续下面的查找步骤。
6. 在bundle的fragment内部类加载器中进行查找,并按照fragment的bundle ID倒序进行查找。如果没有找到,继续下面的步骤。
7. 如果要查找的类被bundle是被导出的或者被bundle导入的,使用(Import-Package or Require- Package),则查找终止,类没有找到。
8. 否则,如果一个类是被使用DynamicImport-Package导入的,则尝试动态导入该类。如果找到一个合适的exporter,则建立一个配线,并转到第3步进行处理。如果动态配线没有建立,则查找失败。
9. 如果dynamic import建立,请求分发给exporting bundle的类加载器。如果exporting bundle的类加载器没有找到类或者资源,则查找失败。