Apache Felix OSGi 使用非bundle jar包共享到其他所有bundle
Contents
使用 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
: 这个是框架本身的加载地方。没有特别研究过。