Atlas插件框架整体设计参考了OSGI,而在OSGI中每一个Bundle会有一个自己的ClassLoader,所以我们需要了解下Atlas中的ClassLoader是怎样设计的,要不然可能经常会遇到ClassNotFoundException。
1.DelegateClassLoader
DelegateClassLoader的初始化是在android.taobao.atlas.framework.Atlas#init方法中,如下图:
① 这里获取当前的ClassLoader是PathClassLoader,这个也是安卓中默认的ClassLoader。
② new一个新的DelegateClassLoader,构造函数传入的是当前的PathClassLoader,也就是DelegateClassLoader的parent ClassLoader。
③ AndroidHack.injectClassLoader(packageName, newClassLoader)方法是把DelegateClassLoader注入到LoadedApk.mClassLoader。这样的话,当发生查找四大组件时就会使用DelegateClassLoader来加载。
2. BundleClassLoader
BundleClassLoader的初始化是在new 每一个BundleImpl中,也就是说会为每个Bundle生成一个BundleClassLoader。如下图:
BundleClassLoader① 在BundleImpl类的resolveBundle方法中生成BundleClassLoader。
② BundleClassLoader的父类是BootClassLoader。
3.BundleClassLoader的类加载顺序
BundleClassLoader.findClass因为BundleClassLoader的parent是BootClassLoader,根据ClassLoader的双亲委托模式,查找顺序如下:
- BootClassLoader。
- findOwnClass,查找Bundle中的class。
- PathClassLoader,宿主apk中的class。
- 当前bundle依赖的bundles中的class。
4.DelegateClassLoader的类加载顺序
DelegateClassLoader.findClassloadFromInstalledBundles这个方法就是通过className找到对应的Bundle,然后再通过BundleClassLoader加载这个class的过程。DelegateClassLoader的parent是PathClassLoader,所以查找顺序如下:
- PathClassLoader,宿主apk中的class。
- 然后就是经过BundleClassLoader的类加载顺序。
之前在使用Atlas中发现,Bundle加载完成之后,在宿主代码中通过Class.forName是找不到Bundle中的class就是这个原因。
5.补充下bundle的so加载
findLibrary① 从宿主系统Path路径中查找。
② 如果没找到,则在当前bundle中的so中查找。
所以对于so的加载,插件也是优先加载宿主的so,然后才是加载插件中的so。宿主是加载不到插件中的so的。
Reference:http://atlas.taobao.org/docs/principle-intro/Runtime_principle.html
网友评论