OSGi Bundle解析源码分析

Bundle的解析过程就是对Bundle的MF文件进行分析,根据配置的依赖关系构造依赖模型。
(源码见:ResolverImpl.resolveBundles0)
假设有2个Bundle,import/export分别是:
BundleA:import pkg.b; export pkg.a; BundleB:import pkg.a; export pkg.b;也就是2个Bundle相互依赖

解析步骤(主要部分):

1、假设首先对BundleA解析,先获取BundleA的所有imports,然后迭代每个import找到匹配的export,并设置import和export的依赖引用关系。
// 设置了依赖引用关系后就知道import是由哪个Bundle导出
export.getExporter().addRef(imp.getBundle());
imp.addPossibleSupplier(export); // 找到pkg.b的一个可能的提供者为BundleB导出的pkg.b
但是,如果自己也export了相同的包,则会被舍弃,会采用它依赖的export。因此,如果一个Bundle import了一个同名的包(自己Bundle也有,而且不管有没有export),则永远不会找到自己包下的类(根据类查找规则,会在依赖的export下寻找)。也就是说,Bundle中包命名一定要注意不要同名。

2、如果export所在的bundle不是已解析(resolved)的,这里的BundleB还没有解析,则开始解析BundleB,同步骤1。
当在解析BundleB的import pkg.a时,发现BundleA还不是已解析(resolved)的(正在解析中resolving),又对BundleA进行解析,同步骤1。
但是,当解析到import pkg.b时,发现它已经有提供者了(前面已经找到了匹配的export),就把该BundleA添加到依赖循环列表中。
这里,BundleA解析结束(没有其他未解析的import了)返回,但状态还是resolving。接着,发现import pkg.a的提供者BundleA为resolving,又把该BundleB添加到依赖循环列表中。
这里,BundleB解析结束(没有其他未解析的import了)返回,但状态还是resolving。

3、循环依赖处理
对解析BundleA涉及的依赖环列表进行依赖检查,如果里面所有Bundle都能正确的找到依赖,则设置它们的状态为已解析(resolved)。

该过程涉及到的相关实体:

Version:表示Bundle或者Package的版本对象。对应的还有个VersionRange,表示版本范围。

VersionSupplier:版本提供者基类,表示一个特定版本的Bundle或者Package(系统可以同时存在多个版本的Bundle或者Package)。

VersionHashMap:用于保存VersionSupplier,它的键为Bundle或者Package的名称,值为与之对应的多个版本构成的数组,定义如下(在父类MappedList中):
	// the mapping with key -> Object[] mapping 
	protected HashMap internal = new HashMap(); 

该对象用来保存系统所有解析的的exports、bundles和generics(在ResolverImpl中实现)。

对于多个版本的情况,是如何处理的呢?实现了Comparator接口,在compare中处理排序逻辑,源码如下:
    // Compares two VersionSuppliers for descending ordered sorts.   
    // The VersionSuppliers are sorted by the following priorities   
    // First the resolution status of the supplying bundle.   
    // Second is the supplier version.   
    // Third is the bundle id of the supplying bundle.   
    public int compare(Object o1, Object o2) {   
        if (!(o1 instanceof VersionSupplier) || !(o2 instanceof VersionSupplier))   
            throw new IllegalArgumentException();   
        VersionSupplier vs1 = (VersionSupplier) o1;   
        VersionSupplier vs2 = (VersionSupplier) o2;   
        // if the selection policy is set then use that   
        if (resolver.getSelectionPolicy() != null)   
            return resolver.getSelectionPolicy().compare(vs1.getBaseDescription(), vs2.getBaseDescription());   
        String systemBundle = resolver.getSystemBundle();   
        // 系统Bundle优先
        if (systemBundle.equals(vs1.getBundle().getSymbolicName()) && !systemBundle.equals(vs2.getBundle().getSymbolicName()))   
            return -1;   
        else if (!systemBundle.equals(vs1.getBundle().getSymbolicName()) && systemBundle.equals(vs2.getBundle().getSymbolicName()))   
            return 1;   
        // 已解析的优先于未解析的
        if (vs1.getBundle().isResolved() != vs2.getBundle().isResolved())   
            return vs1.getBundle().isResolved() ? -1 : 1;  
        // 版本高的优先 
        int versionCompare = -(vs1.getVersion().compareTo(vs2.getVersion()));   
        if (versionCompare != 0)   
            return versionCompare;   
        // Bundle Id小的优先(优先安装的优先)
        return vs1.getBundle().getBundleId() <= vs2.getBundle().getBundleId() ? -1 : 1;   
    }  


BaseDescription:对一个状态的基本描述,所有的描述对象都有一个名称和版本。

VersionConstraint:表示2个Bundle(就require bundle而言)或一个Bundle和一个Package之间的关系(就import/export而言)。
方法isSatisfiedBy(BaseDescription supplier)用来判断约束是否满足。


ResolverConstraint:VersionConstraint辅助类。

GroupingChecker:检查导出包“uses”指令的一致性。 这是一个比较耗时的操作。

猜你喜欢

转载自candy1234.iteye.com/blog/1922959