OSGI 角度理解Atlas 类加载机制

前言:

要想明白Atlas的类加载机制,就要了解OSGI 框架,因为查看Atlas源码会发现Atlas的核心思想就是OSGI。

OSGI

osgi 的主要特点是有灵活的类加载器框架,osgi的bundle类加载器之间只有规则没有固定的委派关系。接下来让我们来看看Atlas的具体类加载规则。

OSGi为每个bundle提供一个类加载器,该加载器能够看到bundle Jar文件内部的类和资源;

Atlas 源码中的实现:
BundleImpl 是OSGI 框架 Bundle的一个具体实现,它的类加载器是怎样实现的呢?

//Framework.java 中安装Bundle的时候创建的Bundle实例
            BundleImpl bundle = null;
            BundleListing.BundleInfo info = AtlasBundleInfoManager.instance().getBundleInfo(location);
            bundle = new BundleImpl(bundleDir, location, in, null, info.getUnique_tag(),true,-1l);

创建实例对象的过程中分析改bundle的依赖关系,然后为改bundle创建一个ClassLoader

    private synchronized void resolveBundle() throws BundleException {

        if (this.archive == null) {
            throw new BundleException("Not a valid bundle: " + location);
        }

        if (this.state == RESOLVED){
            return;
        }

        if ( this.classloader == null){
            // create the bundle classloader
            List<String> dependencies = AtlasBundleInfoManager.instance().getDependencyForBundle(location);
            String nativeLibDir = getArchive().getCurrentRevision().mappingInternalDirectory().getAbsolutePath()+"/lib"+":"
                    + RuntimeVariables.androidApplication.getApplicationInfo().nativeLibraryDir+":"
                    +System.getProperty("java.library.path");
            if(dependencies!=null) {
                for (String str : dependencies) {
                    BundleImpl impl = (BundleImpl) Atlas.getInstance().getBundle(str);
                    if (impl != null) {
                        nativeLibDir += ":";
                        File dependencyLibDir = new File(impl.getArchive().getCurrentRevision().mappingInternalDirectory(), "lib");
                        nativeLibDir += dependencyLibDir;
                    }
                }
            }
            this.classloader = new BundleClassLoader(this,dependencies,nativeLibDir);
        }
        state = RESOLVED;
        // notify the listeners
        Framework.notifyBundleListeners(0 /*LOADED*/, this);
    }

到此为止Bundle的classLoader 创建完成。

为了让bundle能互相协作,可以基于依赖关系,从一个bundle类加载器委托到另一个bundle类加载器。

让我们看看Atlas的具体实现:
1. bundle 会先从自身查找该类(findOwnClass)。
2. 如果没有找到就遍历依赖的bundle
3. 获取依赖bundle的classLoader
4. 查找目标类
5. 如果没有找到抛出ClassNotFoundException

 protected Class<?> findClass(final String classname) throws ClassNotFoundException {

        Class<?> clazz;
        // okay, check if it is in the scope of this classloader
        clazz = findOwnClass(classname);
        if (clazz != null) {

            if (classLoadListener != null) {
                classLoadListener.onClassLoaded(clazz);
            }
            return clazz;
        }
        // find class in PathClassLoader
        try {
            clazz = Framework.systemClassLoader.loadClass(classname);
            if (clazz != null) {
                return clazz;
            }
        } catch (Exception e) {
        }

        // find class in dependency bundle
        if (dependencies != null) {
            for (String dependencyBundle : dependencies) {
                try {
                    BundleImpl impl = (BundleImpl)Atlas.getInstance().getBundle(dependencyBundle);
                    if (impl != null) {
                        clazz = ((BundleClassLoader)impl.getClassLoader()).loadOwnClass(classname);
                        if (clazz != null) {
                            impl.startBundle();
                            return clazz;
                        }
                    } else {
                        Log.e("BundleClassLoader",
                            String.format("%s is not success installed by %s", "" + dependencyBundle, location));
                    }
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }

        throw new ClassNotFoundException(
            "Can't find class " + classname + " in BundleClassLoader: " + bundle.getLocation() + ", dependencies="
                + dependencies + ", thread=" + Thread.currentThread());
    }

总结:
Java和J2EE 的类加载模型都是层次化的,只能委托给上一层的类记载器,而OSGI类加载模型则是网络状的,可以在bundle间互相委托。
例如bundleA、B都依赖于bundleC,当他们访问bundleC中的类时,就会委托给bundleC的类加载器,由它来查找类;如果它发现还要依赖bundleE中的类,就会再委托给bundleE的类加载器。

猜你喜欢

转载自blog.csdn.net/lovebuzhidao/article/details/80326698