Equinox加载Bundle Class的实现

简介:

Equinox在创建Bundle的ClassLoader时,首先获取bundle的classpath,然后执行createBCLPrevileged方法,此方法最后转交由BaseData来创建ClassLoader。

  BaseDate创建ClassLoader的关键代码片段为:

ClassLoadingHook[] hooks = adaptor.getHookRegistry().getClassLoadingHooks();      ClassLoader parent = adaptor.getBundleClassLoaderParent();      BaseClassLoader cl = null     for (int i = 0; i < hooks.length && cl == null; i++)         cl = hooks[i].createClassLoader(parent, delegate, domain, this, bundleclasspath);      if (cl == null        cl = new DefaultClassLoader(parent, delegate, domain, this, bundleclasspath);      return cl;

  在Equinox中,默认的情况下adaptor.getBundleClassLoaderParent返回的为bootstrap classloader,可通过修改启动的osgi.parentClassLoader 来改变这个parent classloader,

  osgi.parentClassLoader 的可选值有四个,分别是:

  ● boot:默认

  ● app:SystemClassLoader

  ● ext:SystemClassLoader的parent

  ● fwk:启动Equinox的ClassLoader

  ClassLoadingHook在createClassLoader的时候都没有做动作,因此最后ClassLoader都是通过创建DefaultClassLoader对象来构建的,其中parent参数为null,delegate参数为BundleLoader实例,bundleclasspath参数为bundle的classpath。

  经过以上步骤后,完成了ClassLoader的创建,可以开始加载class了,根据上面上述,Bundle的Class就由DefaultClassLoader来完成了。

  查看DefaultClassLoader的loadClass代码,发现真正的加载class的过程是转为调用了delegate 的findClass来完成的,delegate参数对应的为BundleLoader实例,转为跟踪BundleLoader的findClass方法。

  BundleLoader的findClass方法的代码片段:

if (checkParent && parentCL != null && name.startsWith(JAVA_PACKAGE))     return parentCL.loadClass(name);

  从以上这个代码片段,可以看到,Equinox将java.开头的类转交给了parent classloader去加载,这也意味着没必要在系统中提供对外export java.开头的package。

  如果不是java.开头的类,则交由findClassInternal方法来完成加载。

  findClassInternal方法遵循的为OSGi规范中定义的Class的加载顺序,不过仍然稍有改动:

  1)判断是否交由parent classloader去完成加载

  在启动Equinox时,Equinox会读取org.osgi.framework.bootdelegation属性,该属性对应配置的为需要从parent classloader中加载的package,如值配置的为*,说明所有的都从parent classloader中加载 ,如值配置的为具体的package,那么则放入bootDelegation集合;如配置的为带通配符的package,那么则放入bootDelegationStems集合。

  判断时Equinox首先判断是否所有的都从parent classloader中加载,如是则从parent classloader中加载;

  如需要加载的类的package位于bootDelegation或bootDelegationStems集合中,那么同样从parent classloader中加载。

  如不从parent classloader中加载,则进入下面的步骤。

 2)尝试调用Equinox提供的ClassLoaderDelegateHook的扩展来加载

  Equinox对外提供了ClassLoaderDelegateHook的接口扩展,可编写ClassLoaderDelegateHook的实现,注册到Framework中,那么当有Class需要加载等动作时都会得到通知。

  在默认情况下,Equinox中没有ClassLoaderDelegateHook的实现,因此继续下面的步骤。

  3)判断是否在import-package中,如在则交由相应的PackageSource去加载

  根据Bundle配置的import-package,判断目前需要加载的类是否在import-package中,如在则交由对应的PackageSource进行加载,PackageSource在加载时即直接交由对应的Bundle的classloader去加载,如加载的类的package在import-package中,但加载后仍然没有找到Class,则直接抛出ClassNotFoundException,如加载到,则直接返回。

  如所需要加载的类的package不在import-package中,则继续下面的步骤。

  4)尝试从require-bundle中加载

  尝试使用require-bundle来加载,如加载到,则直接返回,如加载不到,则继续下面的步骤。

  5)尝试从当前Bundle中加载

  直到经过以上步骤的尝试,才尝试由当前Bundle中加载,当前Bundle加载的方法即从Bundle-Classpath或当前Bundle的Fragment中查找相应名称的class文件,并读取该文件进行加载,如class文件已加载,则进行缓存,再次加载时则不需要查找和解析class文件。

  如从当前Bundle中仍然未找到所需的类,则继续下面的步骤。

  6)尝试从DynamicImport-Package中加载

  判断需要找的类的package是否在DynamicImport-Package中,如果在,则交由相应的PackageSource进行加载,如PackageSource中加载不到,则抛出ClassNotFoundException;如不在DynamicImport-Package中,则继续下面的步骤。

  7)再次尝试调用Equinox提供的ClassLoaderDelegateHook的扩展来加载

  这步和第2)步相同,因此在默认情况下继续下面的步骤。

  8)尝试使用eclipse的buddy机制来加载

  Buddy机制是Eclipse的扩展,并不符合OSGi规范,因此在此不做深入分析。

  9)判断一定的条件,如符合则从parent classloader中加载

  判断的条件为:parent classloader不为null、不从parent classloader中加载、Equinox的向后兼容属性(osgi.compatibility.bootdelegation)为true以及jvm的bug class,如满足以上条件,则尝试从parent classloader中加载。

  如经过以上所有步骤后,仍然未找到需要加载的class,则抛出ClassNotFoundException。

  从上面的代码分析中,在Equinox中可以通过osgi.parentClassLoader、org.osgi.framework.bootdelegation来控制从Bundle ClassLoader外来加载Class,这对于集成Equinox其他容器而言,非常有用,另外,还可以通过实现ClassLoaderDelegateHook来改变Class的加载。


本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/

目录
相关文章
|
8月前
|
应用服务中间件 Linux Windows
tomcat部署web项目报错:Could not initialize class sun.awt.X11GraphicsEnvironment
tomcat部署web项目报错:Could not initialize class sun.awt.X11GraphicsEnvironment
188 0
|
API Android开发
Android studio:导入新类提示Add library ‘Gradle*****@aar‘ to classpath
Android studio:导入新类提示Add library ‘Gradle*****@aar‘ to classpath
191 0
错误: 找不到或无法加载主类 org.apache.tools.ant.launch.Launcher
错误: 找不到或无法加载主类 org.apache.tools.ant.launch.Launcher
109 0
|
Java 数据库 Android开发
在添加greendao 的plugin 出现?:Could not initialize class com.android.sdklib.repository
在添加greendao 的plugin 出现?:Could not initialize class com.android.sdklib.repository
255 1
在添加greendao 的plugin 出现?:Could not initialize class com.android.sdklib.repository
|
Android开发
【Android 逆向】启动 DEX 字节码中的 Activity 组件 ( 替换 LoadedApk 中的类加载器 | 加载 DEX 文件中的 Activity 类并启动成功 )(二)
【Android 逆向】启动 DEX 字节码中的 Activity 组件 ( 替换 LoadedApk 中的类加载器 | 加载 DEX 文件中的 Activity 类并启动成功 )(二)
235 0
|
安全 Java Android开发
【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )(三)
【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )(三)
116 0
|
安全 Java Android开发
【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )(二)
【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )(二)
95 0
|
安全 Java Android开发
【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )(一)
【Android 安全】DEX 加密 ( Application 替换 | 分析 Activity 组件中获取的 Application | ActivityThread | LoadedApk )(一)
158 0
|
缓存 Ubuntu Java
Android插件化开发之DexClassLoader动态加载dex、jar小Demo
Android插件化开发之DexClassLoader动态加载dex、jar小Demo
241 0
Android插件化开发之DexClassLoader动态加载dex、jar小Demo
when is extension component&#39;s resource bundle loaded
Created by Wang, Jerry, last modified on May 20, 2015
85 0
when is extension component&#39;s resource bundle loaded

热门文章

最新文章