外部启动equinox

equinox的jar包本身就有Main-Class,可以直接运行,例如:

java -jar org.eclipse.osgi-3.5.1.R35x_v20090827.jar

但是这种运行方式,需要在configuration/config.ini文件里面配置osgi.bundles参数,要把每个需要启动的bundle名填进去,这么手残的方式显然不科学。


所幸可以从外部启动equinox,只要EclipseStarter.run就可以了。

在这之前,需要配置好参数。可以写段代码,搜索某个指定目录(我用的目录名plugins)下的全部jar包作为bundle,然后构造出 osgi.bundles 这个参数。

例如:


package test;

import java.io.File;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.core.runtime.adaptor.EclipseStarter;
import org.eclipse.osgi.framework.internal.core.FrameworkProperties;

public class Main {
	public static void main(String[] args) throws Exception {
		String pluginPath = new File("").getCanonicalPath() + File.separator
				+ "plugins";
		FrameworkProperties.setProperty("osgi.noShutdown", "true");
		FrameworkProperties.setProperty("eclipse.ignoreApp", "true");
		FrameworkProperties.setProperty("osgi.bundles.defaultStartLevel", "4");
		FrameworkProperties.setProperty("osgi.bundles", getPlugins(pluginPath));
		FrameworkProperties.setProperty("osgi.syspath", pluginPath);
		File config = new File(new File("").getCanonicalPath() + File.separator
				+ "configuration");
		if (config.exists()) {
			deleteDirectory(config.getCanonicalPath());
		}
		EclipseStarter.run(new String[] { "-configuration", "configuration",
				"-console" }, null);
	}

	private static void deleteDirectory(String sPath) {
		// 如果sPath不以文件分隔符结尾,自动添加文件分隔符
		if (!sPath.endsWith(File.separator)) {
			sPath = sPath + File.separator;
		}
		File dirFile = new File(sPath);
		// 如果dir对应的文件不存在,或者不是一个目录,则退出
		if (!dirFile.exists() || !dirFile.isDirectory()) {
			return;
		}
		// 删除文件夹下的所有文件(包括子目录)
		File[] files = dirFile.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 删除子文件
			if (files[i].isFile()) {
				deleteFile(files[i].getAbsolutePath());
			} // 删除子目录
			else {
				deleteDirectory(files[i].getAbsolutePath());
			}
		}
		dirFile.delete();
	}

	private static void deleteFile(String sPath) {
		File file = new File(sPath);
		// 路径为文件且不为空则进行删除
		if (file.isFile() && file.exists()) {
			file.delete();
		}
	}

	private static String getPlugins(String pluginPath) {
		StringBuilder sb = new StringBuilder();
		File dir = new File(pluginPath);
		Pattern pat = Pattern.compile("-[\\d]+\\.[\\d]+\\.[\\d]+");
		for (File file : dir.listFiles()) {
			String fileName = file.getName();
			if (fileName.endsWith(".jar")) {
				Matcher mat = pat.matcher(fileName);
				if (mat.find()) {
					sb.append(fileName.substring(0, mat.start())).append(
							"@start,");
				}
			}
		}
		return sb.substring(0, sb.length() - 1);
	}
}



在导出jar包的时候,遇到一些问题。以前真没注意。

eclipse导出Runnable jar时,会把全部依赖一起加到这个jar包里面来,让这个jar包不依赖其他任何jar包,就能独立运行。

这显然不是我需要的。


而导出一般的jar包,你还是可以选Main-Class。在MENIFEST.MF中,会产生这么一个属性。它其实也是Runnable的,只是需要依赖。


比如我导出的jar包名字叫start.jar,然后我就用这么一个命令企图让它运行起来:

java -cp org.eclipse.osgi-3.5.1.R35x_v20090827.jar -jar start.jar

失败了。。。。NoClassDefFoundError。。。


查了一会儿才知道,java命令在运行jar包的时候,是忽略掉classpath参数的。这样的逻辑:假如classpath后面跟了两个jar包,都输出了同一个类,而类加载器只要找到第一个类,就认了。那么运行时就可能出现有悖于编程者意图情况。所以干脆不支持classpath大混杂的参数。


要让它运行起来,需要在MENIFEST.MF中,加入Class-Path参数。

比如Class-Path: org.eclipse.osgi-3.5.1.R35x_v20090827.jar

如果有多个依赖,用空格分开。


好了现在可以用命令行轻松启动许多bundle了。

然后看一下类加载器的情况:

package test;

public class Util {
	public static void pringClassLoader(Object obj) {
		ClassLoader cl = obj.getClass().getClassLoader();
		while (cl != null) {
			System.out.println(cl);
			cl = cl.getParent();
		}
	}
}

在三个地方打印:

EclipseStarter启动

某自产bundle1

某自产bundle2


得到如下结果:

start sys bundle :
sun.misc.Launcher$AppClassLoader@1dd3812
sun.misc.Launcher$ExtClassLoader@8c436b


start producer bunde :
org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@8cc09a
org.eclipse.osgi.baseadaptor.BaseAdaptor$ParentClassLoader@928095


start consumer bundle :
org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@b8db77
org.eclipse.osgi.baseadaptor.BaseAdaptor$ParentClassLoader@928095


随便分析一下,EclipseStarter这个地方,是java程序入口,由AppClassLoader加载毫无疑问。

另外俩自产bundle,类加载器都是DefaultClassLoader,并且实例不同,但是它们的父加载器BaseAdaptor$ParentClassLoader却是相同的实例。

这就为应用程序提供了一个基本的设计思路,工具类、不需要启动、不需要拆装的jar包,可以由统一父类加载,被任意bundle调用。而各个业务模块,为不同加载器,被osgi隔离。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值