使用 org.osgi.framework.system.packages 参数

创建一个项目,假设使用了Google的Guava的bundle,但这个库并不是OSGi Bundle。但如果又想共享于其他bundle的话,可以按以下方式来处理。

在IDE里,添加buildpath,添加这个Guava类库(为了编译通过,亲)。然后记得在自己的Bundle里,修改MANIFEST.MF文件,Import-Package自己使用了哪些包,比如下面的例子:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: UseGuava
Bundle-SymbolicName: UseGuava
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: useguava.Activator
Bundle-Vendor: yangzhiyong
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.osgi.framework;version="1.3.0",
 com.google.common.base

使用Guava的Bundle源码:

package useguava;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

import com.google.common.base.Strings;

public class Activator implements BundleActivator {

	private static BundleContext context;

	static BundleContext getContext() {
		return context;
	}

	public void start(BundleContext bundleContext) throws Exception {
		Activator.context = bundleContext;
		System.out.println("start bundle");
		System.out.println(Strings.repeat("fuck", 10));

	}

	public void stop(BundleContext bundleContext) throws Exception {
		Activator.context = null;
		System.out.println("stop bundle");
	}

}

然后,在启动OSGi时,添加以下参数。这里以apache felix为例:

➜  felix-framework-5.2.0  rm felix-cache -rf  &&  java -Dorg.osgi.framework.system.packages.extra=com.google.common.base -cp "bin/*" org.apache.felix.main.Main
____________________________
Welcome to Apache Felix Gogo

g! start file:'/tmp/plugins/UseGuava_1.0.0.201509141006.jar'
start bundle
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuck
g!

总结

添加参数:-Dorg.osgi.framework.system.packages.extra,用逗号分开每个要导出(相当于Export-Packages),然后在各个Bundle,按需要使用Import-Packages即可。 还要注意classpath的配置,要添加相应的classpath,让java启动时,找到这个jar包即可。

使用org.osgi.framework.bootdelegation 参数

和以上的方式差不多。最重要的一点是:不要在Bundle里,添加 Import-Packages 来导入这在org.osgi.framework.bootdelegation参数里配置的包。千万记得不要Import-Packages

还有,也要添加下org.osgi.framework.bundle.parent参数。完整启动参数如下:

我这里,只是将上面那个MF文件,去掉了相应的Import-Packages,内容如下:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: UseGuava
Bundle-SymbolicName: UseGuava
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: useguava.Activator
Bundle-Vendor: yangzhiyong
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.osgi.framework;version="1.3.0"

然后启动时如下:

➜  felix-framework-5.2.0  rm felix-cache -rf  &&  java -Dorg.osgi.framework.bundle.parent=app -Dorg.osgi.framework.bootdelegation="com.google.common.base" -cp "bin/*"  org.apache.felix.main.Main
____________________________
Welcome to Apache Felix Gogo

g! start file:'/tmp/plugins/UseGuava_1.0.0.201509141006.jar'
start bundle
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuck
g!

注意:org.osgi.framework.bundle.parent参数,默认值是boot,如果没有修改为app的话,启动会报错。如下:

➜  felix-framework-5.2.0  rm felix-cache -rf  &&  java -Dorg.osgi.framework.bundle.parent=boot -Dorg.osgi.framework.bootdelegation="com.google.common.base" -cp "bin/*"  org.apache.felix.main.Main
____________________________
Welcome to Apache Felix Gogo

g! start file:'/tmp/plugins/UseGuava_1.0.0.201509141006.jar'
start bundle
org.osgi.framework.BundleException: Activator start error in bundle UseGuava [5].
	at org.apache.felix.framework.Felix.activateBundle(Felix.java:2270)
	at org.apache.felix.framework.Felix.startBundle(Felix.java:2138)
	at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:977)
	at org.apache.felix.gogo.command.Basic.start(Basic.java:729)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137)
	at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:82)
	at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:480)
	at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:406)
	at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)
	at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:182)
	at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:119)
	at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:94)
	at org.apache.felix.gogo.shell.Console.run(Console.java:62)
	at org.apache.felix.gogo.shell.Shell.console(Shell.java:203)
	at org.apache.felix.gogo.shell.Shell.gosh(Shell.java:128)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137)
	at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:82)
	at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:480)
	at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:406)
	at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108)
	at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:182)
	at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:119)
	at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:94)
	at org.apache.felix.gogo.shell.Activator.run(Activator.java:75)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: com/google/common/base/Strings
	at useguava.Activator.start(Activator.java:19)
	at org.apache.felix.framework.util.SecureAction.startActivator(SecureAction.java:697)
	at org.apache.felix.framework.Felix.activateBundle(Felix.java:2220)
	... 32 more
Caused by: java.lang.ClassNotFoundException: com.google.common.base.Strings not found by UseGuava [5]
	at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1558)
	at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:79)
	at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1998)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
	... 35 more
java.lang.NoClassDefFoundError: com/google/common/base/Strings
g!

虽然我们使用了-cp来添加我们的jar包,但由于这个参数是boot(默认就是它),所以,它只会加载-Dsun.boot.class.path参数的jar包,而忽略-cp的指定的jar包,所以导致ClassNotFoundException.

如果确定想使用-Dorg.osgi.framework.bundle.parent=boot的话(默认情况也是这样子),就要修改为以下:

➜  felix-framework-5.2.0  rm felix-cache -rf  &&  java -Dsun.boot.class.path="/home/yang/Java/jdk1.8.0_51/jre/lib/resources.jar:/home/yang/Java/jdk1.8.0_51/jre/lib/rt.jar:/home/yang/Java/jdk1.8.0_51/jre/lib/sunrsasign.jar:/home/yang/Java/jdk1.8.0_51/jre/lib/jsse.jar:/home/yang/Java/jdk1.8.0_51/jre/lib/jce.jar:/home/yang/Java/jdk1.8.0_51/jre/lib/charsets.jar:/home/yang/Java/jdk1.8.0_51/jre/lib/jfr.jar:/home/yang/Java/jdk1.8.0_51/jre/classes:bin/guava-19.0-rc1.jar" -Dorg.osgi.framework.bundle.parent=boot -Dorg.osgi.framework.bootdelegation="com.google.common.base" -cp "bin/*"  org.apache.felix.main.Main
____________________________
Welcome to Apache Felix Gogo

g! start file:'/tmp/plugins/UseGuava_1.0.0.201509141006.jar'
start bundle
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuck
g!

-Dorg.osgi.framework.bundle.parent这个参数的数值可以有四个:

boot: 就是上面那个例子,这个在-Dsun.boot.class.path修改(即加载java.及Java的核心类库),然后再添加上你自己的jar包的类库就可以了。(上面就是这样,在原来的,添加多了Guava的jar包)。默认情况下它主要加载的是rt.jar以及其他在jre/lib目录下的jar包。

ext: 这个主要加载jre/lib/ext目录下的jar包。这个虽然没有环境变量可以配置,但可以通过修改-Djava.ext.dirs参数来修改。比如,使用ext来加载时的启动例子如下:(注意,使用ext时,就不要配置-Dsun.boot.class.path了,而是配置-Djava.ext.dirs了.

➜  felix-framework-5.2.0  rm felix-cache -rf  &&  java -Djava.ext.dirs="/home/yang/Java/jdk1.8.0_51/jre/lib/ext:/usr/java/packages/lib/ext:mylib" -Dorg.osgi.framework.bundle.parent=ext -Dorg.osgi.framework.bootdelegation="com.google.common.base" -cp "bin/*"  org.apache.felix.main.Main
____________________________
Welcome to Apache Felix Gogo

g! start file:'/tmp/plugins/UseGuava_1.0.0.201509141006.jar'
start bundle
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuck
g!

app: 这个主要加载的是CLASSPATH环境变量的类。注意,使用-cp指定时,它会覆盖系统里的CLASSPATH的值。使用app的启动例子如下:

➜  felix-framework-5.2.0  rm felix-cache -rf  &&  java -Dorg.osgi.framework.bundle.parent=app -Dorg.osgi.framework.bootdelegation="com.google.common.base" -cp "bin/*:mylib/*"  org.apache.felix.main.Main
____________________________
Welcome to Apache Felix Gogo

g! start file:'/tmp/plugins/UseGuava_1.0.0.201509141006.jar'
start bundle
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuck
g!

framework: 这个是框架本身的加载地方。没有特别研究过。

关于java如何找class的官方文档