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的依赖引用关系。
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中):
该对象用来保存系统所有解析的的exports、bundles和generics(在ResolverImpl中实现)。
对于多个版本的情况,是如何处理的呢?实现了Comparator接口,在compare中处理排序逻辑,源码如下:
BaseDescription:对一个状态的基本描述,所有的描述对象都有一个名称和版本。
VersionConstraint:表示2个Bundle(就require bundle而言)或一个Bundle和一个Package之间的关系(就import/export而言)。
ResolverConstraint:VersionConstraint辅助类。
GroupingChecker:检查导出包“uses”指令的一致性。 这是一个比较耗时的操作。
(源码见: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”指令的一致性。 这是一个比较耗时的操作。