(源码见: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”指令的一致性。 这是一个比较耗时的操作。